Merge "Add device config tests to GameManagerServiceTests" into sc-dev
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 284e807..23dc720 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -123,13 +123,19 @@
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/public/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/public/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -137,21 +143,18 @@
],
}
-priv_apps =
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+priv_apps = " --show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\)"
-priv_apps_in_stubs =
- " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+priv_apps_in_stubs = " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\)"
test = " --show-annotation android.annotation.TestApi"
-module_libs =
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+module_libs = " --show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
"\\)"
droidstubs {
@@ -166,7 +169,7 @@
last_released: {
api_file: ":android-non-updatable.api.system.latest",
removed_api_file: ":android-non-updatable-removed.api.system.latest",
- baseline_file: ":android-non-updatable-incompatibilities.api.system.latest"
+ baseline_file: ":android-non-updatable-incompatibilities.api.system.latest",
},
api_lint: {
enabled: true,
@@ -176,13 +179,19 @@
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -206,25 +215,37 @@
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "android.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "removed.txt",
tag: ".removed-api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/test/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -252,13 +273,19 @@
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/module-lib/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/module-lib/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -318,10 +345,13 @@
java_version: "1.8",
compile_dex: true,
dist: {
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
tag: ".jar",
dest: "android-non-updatable.jar",
- }
+ },
}
java_library_static {
@@ -337,7 +367,7 @@
java_library_static {
name: "android-non-updatable.stubs.system",
defaults: ["android-non-updatable_defaults_stubs_current"],
- srcs: [ ":system-api-stubs-docs-non-updatable" ],
+ srcs: [":system-api-stubs-docs-non-updatable"],
libs: modules_system_stubs,
dist: {
dir: "apistubs/android/system",
@@ -380,7 +410,10 @@
java_defaults {
name: "android_stubs_dists_default",
dist: {
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
tag: ".jar",
dest: "android.jar",
},
@@ -411,7 +444,10 @@
dists: [
{
// Legacy dist path
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
tag: ".jar",
dest: "android_system.jar",
},
@@ -433,14 +469,6 @@
dist: {
dir: "apistubs/android/test",
},
- dists: [
- {
- // Legacy dist path
- targets: ["sdk", "win_sdk"],
- tag: ".jar",
- dest: "android_test.jar",
- },
- ],
}
java_library_static {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
index b66837d..b06e215 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
@@ -37,6 +37,8 @@
* @param <ValueType> The type of result object for successful calls.
*/
public final class AppSearchResult<ValueType> implements Parcelable {
+ private static final String TAG = "AppSearchResult";
+
/**
* Result codes from {@link AppSearchSession} methods.
* @hide
@@ -246,14 +248,22 @@
@NonNull
public static <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
@NonNull Throwable t) {
- Log.d("AppSearchResult", "Converting throwable to failed result.", t);
+ // Log for traceability. NOT_FOUND is logged at VERBOSE because this error can occur during
+ // the regular operation of the system (b/183550974). Everything else is logged at DEBUG.
+ if (t instanceof AppSearchException
+ && ((AppSearchException) t).getResultCode() == RESULT_NOT_FOUND) {
+ Log.v(TAG, "Converting throwable to failed result: " + t);
+ } else {
+ Log.d(TAG, "Converting throwable to failed result.", t);
+ }
if (t instanceof AppSearchException) {
return ((AppSearchException) t).toAppSearchResult();
}
+ String exceptionClass = t.getClass().getSimpleName();
@AppSearchResult.ResultCode int resultCode;
- if (t instanceof IllegalStateException) {
+ if (t instanceof IllegalStateException || t instanceof NullPointerException) {
resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
} else if (t instanceof IllegalArgumentException) {
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
@@ -262,6 +272,6 @@
} else {
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
}
- return AppSearchResult.newFailedResult(resultCode, t.getMessage());
+ return AppSearchResult.newFailedResult(resultCode, exceptionClass + ": " + t.getMessage());
}
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index ac91bdb..c85c4c3 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -19,9 +19,9 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.util.SchemaMigrationUtil;
import android.os.Bundle;
-import android.os.ParcelableException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -274,12 +274,14 @@
mService.putDocuments(mPackageName, mDatabaseName, documentBundles, mUserId,
/*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime(),
new IAppSearchBatchResultCallback.Stub() {
+ @Override
public void onResult(AppSearchBatchResult result) {
executor.execute(() -> callback.onResult(result));
}
- public void onSystemError(ParcelableException exception) {
- executor.execute(() -> callback.onSystemError(exception.getCause()));
+ @Override
+ public void onSystemError(AppSearchResult result) {
+ executor.execute(() -> sendSystemErrorToCallback(result, callback));
}
});
mIsMutated = true;
@@ -321,6 +323,7 @@
request.getProjectionsInternal(),
mUserId,
new IAppSearchBatchResultCallback.Stub() {
+ @Override
public void onResult(AppSearchBatchResult result) {
executor.execute(() -> {
AppSearchBatchResult.Builder<String, GenericDocument>
@@ -359,8 +362,9 @@
});
}
- public void onSystemError(ParcelableException exception) {
- executor.execute(() -> callback.onSystemError(exception.getCause()));
+ @Override
+ public void onSystemError(AppSearchResult result) {
+ executor.execute(() -> sendSystemErrorToCallback(result, callback));
}
});
} catch (RemoteException e) {
@@ -515,12 +519,14 @@
mService.removeByUri(mPackageName, mDatabaseName, request.getNamespace(),
new ArrayList<>(request.getUris()), mUserId,
new IAppSearchBatchResultCallback.Stub() {
+ @Override
public void onResult(AppSearchBatchResult result) {
executor.execute(() -> callback.onResult(result));
}
- public void onSystemError(ParcelableException exception) {
- executor.execute(() -> callback.onSystemError(exception.getCause()));
+ @Override
+ public void onSystemError(AppSearchResult result) {
+ executor.execute(() -> sendSystemErrorToCallback(result, callback));
}
});
mIsMutated = true;
@@ -817,4 +823,21 @@
}
});
}
+
+ /**
+ * Calls {@link BatchResultCallback#onSystemError} with a throwable derived from the given
+ * failed {@link AppSearchResult}.
+ *
+ * <p>The {@link AppSearchResult} generally comes from
+ * {@link IAppSearchBatchResultCallback#onSystemError}.
+ *
+ * <p>This method should be called from the callback executor thread.
+ */
+ private void sendSystemErrorToCallback(
+ @NonNull AppSearchResult<?> failedResult, @NonNull BatchResultCallback<?, ?> callback) {
+ Preconditions.checkArgument(!failedResult.isSuccess());
+ Throwable throwable = new AppSearchException(
+ failedResult.getResultCode(), failedResult.getErrorMessage());
+ callback.onSystemError(throwable);
+ }
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/BatchResultCallback.java b/apex/appsearch/framework/java/android/app/appsearch/BatchResultCallback.java
index 49049b6..28f8a7a 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/BatchResultCallback.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/BatchResultCallback.java
@@ -36,13 +36,23 @@
void onResult(@NonNull AppSearchBatchResult<KeyType, ValueType> result);
/**
- * Called when a system error occurred.
+ * Called when a system error occurs.
*
- * @param throwable The cause throwable.
+ * <p>This method is only called the infrastructure is fundamentally broken or unavailable, such
+ * that none of the requests could be started. For example, it will be called if the AppSearch
+ * service unexpectedly fails to initialize and can't be recovered by any means, or if
+ * communicating to the server over Binder fails (e.g. system service crashed or device is
+ * rebooting).
+ *
+ * <p>The error is not expected to be recoverable and there is no specific recommended action
+ * other than displaying a permanent message to the user.
+ *
+ * <p>Normal errors that are caused by invalid inputs or recoverable/retriable situations
+ * are reported associated with the input that caused them via the {@link #onResult} method.
+ *
+ * @param throwable an exception describing the system error
*/
default void onSystemError(@Nullable Throwable throwable) {
- if (throwable != null) {
- throw new RuntimeException(throwable);
- }
+ throw new RuntimeException("Unrecoverable system error", throwable);
}
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
index b1bbd18..64b331e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
@@ -16,10 +16,10 @@
package android.app.appsearch;
import android.app.appsearch.AppSearchBatchResult;
-import android.os.ParcelableException;
+import android.app.appsearch.AppSearchResult;
/** {@hide} */
oneway interface IAppSearchBatchResultCallback {
void onResult(in AppSearchBatchResult result);
- void onSystemError(in ParcelableException exception);
-}
\ No newline at end of file
+ void onSystemError(in AppSearchResult result);
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
index 27729a5..299c9957 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
@@ -16,9 +16,8 @@
package android.app.appsearch;
import android.app.appsearch.AppSearchResult;
-import android.os.ParcelableException;
/** {@hide} */
oneway interface IAppSearchResultCallback {
void onResult(in AppSearchResult result);
-}
\ No newline at end of file
+}
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 a8048dc..2368bdb 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -51,7 +51,7 @@
/** @hide */
public AppSearchSchema(@NonNull Bundle bundle) {
- Preconditions.checkNotNull(bundle);
+ Objects.requireNonNull(bundle);
mBundle = bundle;
}
@@ -125,7 +125,7 @@
/** Creates a new {@link AppSearchSchema.Builder}. */
public Builder(@NonNull String schemaType) {
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(schemaType);
mSchemaType = schemaType;
}
@@ -133,7 +133,7 @@
@NonNull
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(propertyConfig);
+ Objects.requireNonNull(propertyConfig);
String name = propertyConfig.getName();
if (!mPropertyNames.add(name)) {
throw new IllegalSchemaException("Property defined more than once: " + name);
@@ -246,7 +246,7 @@
@Nullable private Integer mHashCode;
PropertyConfig(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
@Override
@@ -712,7 +712,7 @@
/** Returns the logical schema-type of the contents of this document property. */
@NonNull
public String getSchemaType() {
- return Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+ return Objects.requireNonNull(mBundle.getString(SCHEMA_TYPE_FIELD));
}
/**
@@ -755,7 +755,7 @@
@NonNull
public DocumentPropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(schemaType);
mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
return this;
}
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 8c9d950..e3b3a85 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
/**
@@ -101,11 +102,11 @@
* @hide
*/
public GenericDocument(@NonNull Bundle bundle) {
- Preconditions.checkNotNull(bundle);
+ Objects.requireNonNull(bundle);
mBundle = bundle;
- mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
- mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
- mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+ mProperties = Objects.requireNonNull(bundle.getParcelable(PROPERTIES_FIELD));
+ mUri = Objects.requireNonNull(mBundle.getString(URI_FIELD));
+ mSchemaType = Objects.requireNonNull(mBundle.getString(SCHEMA_TYPE_FIELD));
mCreationTimestampMillis =
mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD, System.currentTimeMillis());
}
@@ -199,7 +200,7 @@
*/
@Nullable
public Object getProperty(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
Object property = mProperties.get(key);
if (property instanceof ArrayList) {
return getPropertyBytesArray(key);
@@ -218,7 +219,7 @@
*/
@Nullable
public String getPropertyString(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
String[] propertyArray = getPropertyStringArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return null;
@@ -235,7 +236,7 @@
* there is no such key or the value is of a different type.
*/
public long getPropertyLong(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
long[] propertyArray = getPropertyLongArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return 0;
@@ -252,7 +253,7 @@
* if there is no such key or the value is of a different type.
*/
public double getPropertyDouble(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
double[] propertyArray = getPropertyDoubleArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return 0.0;
@@ -269,7 +270,7 @@
* false} if there is no such key or the value is of a different type.
*/
public boolean getPropertyBoolean(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
boolean[] propertyArray = getPropertyBooleanArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return false;
@@ -287,7 +288,7 @@
*/
@Nullable
public byte[] getPropertyBytes(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
byte[][] propertyArray = getPropertyBytesArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return null;
@@ -305,7 +306,7 @@
*/
@Nullable
public GenericDocument getPropertyDocument(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
GenericDocument[] propertyArray = getPropertyDocumentArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return null;
@@ -342,7 +343,7 @@
*/
@Nullable
public String[] getPropertyStringArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, String[].class);
}
@@ -355,7 +356,7 @@
*/
@Nullable
public long[] getPropertyLongArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, long[].class);
}
@@ -368,7 +369,7 @@
*/
@Nullable
public double[] getPropertyDoubleArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, double[].class);
}
@@ -381,7 +382,7 @@
*/
@Nullable
public boolean[] getPropertyBooleanArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, boolean[].class);
}
@@ -396,7 +397,7 @@
@Nullable
@SuppressWarnings("unchecked")
public byte[][] getPropertyBytesArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
if (bundles == null || bundles.size() == 0) {
return null;
@@ -428,7 +429,7 @@
@SuppressLint("ArrayReturn")
@Nullable
public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
Parcelable[] bundles = getAndCastPropertyArray(key, Parcelable[].class);
if (bundles == null || bundles.length == 0) {
return null;
@@ -591,9 +592,9 @@
*/
@SuppressWarnings("unchecked")
public Builder(@NonNull String namespace, @NonNull String uri, @NonNull String schemaType) {
- Preconditions.checkNotNull(namespace);
- Preconditions.checkNotNull(uri);
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(namespace);
+ Objects.requireNonNull(uri);
+ Objects.requireNonNull(schemaType);
mBuilderTypeInstance = (BuilderType) this;
mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
mBundle.putString(GenericDocument.URI_FIELD, uri);
@@ -682,8 +683,8 @@
@NonNull
public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -694,15 +695,14 @@
*
* @param key the key associated with the {@code values}.
* @param values the {@code boolean} values of the property.
- * @throws IllegalArgumentException if no values are provided or if values exceed maximum
- * repeated property length.
+ * @throws IllegalArgumentException if values exceed maximum repeated property length.
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -712,15 +712,14 @@
*
* @param key the key associated with the {@code values}.
* @param values the {@code long} values of the property.
- * @throws IllegalArgumentException if no values are provided or if values exceed maximum
- * repeated property length.
+ * @throws IllegalArgumentException if values exceed maximum repeated property length.
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -730,15 +729,14 @@
*
* @param key the key associated with the {@code values}.
* @param values the {@code double} values of the property.
- * @throws IllegalArgumentException if no values are provided or if values exceed maximum
- * repeated property length.
+ * @throws IllegalArgumentException if values exceed maximum repeated property length.
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -755,8 +753,8 @@
@NonNull
public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -776,8 +774,8 @@
public BuilderType setPropertyDocument(
@NonNull String key, @NonNull GenericDocument... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -850,9 +848,7 @@
}
private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
- if (length == 0) {
- throw new IllegalArgumentException("The input array is empty.");
- } else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
+ if (length > MAX_REPEATED_PROPERTY_LENGTH) {
throw new IllegalArgumentException(
"Repeated property \""
+ key
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
index 1719e14..4dc3225 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
@@ -28,6 +28,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -52,9 +53,9 @@
@NonNull String namespace,
@NonNull Set<String> uris,
@NonNull Map<String, List<String>> typePropertyPathsMap) {
- mNamespace = Preconditions.checkNotNull(namespace);
- mUris = Preconditions.checkNotNull(uris);
- mTypePropertyPathsMap = Preconditions.checkNotNull(typePropertyPathsMap);
+ mNamespace = Objects.requireNonNull(namespace);
+ mUris = Objects.requireNonNull(uris);
+ mTypePropertyPathsMap = Objects.requireNonNull(typePropertyPathsMap);
}
/** Returns the namespace attached to the request. */
@@ -114,7 +115,7 @@
/** Creates a {@link GetByUriRequest.Builder} instance. */
public Builder(@NonNull String namespace) {
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -124,7 +125,7 @@
*/
@NonNull
public Builder addUris(@NonNull String... uris) {
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
return addUris(Arrays.asList(uris));
}
@@ -136,7 +137,7 @@
@NonNull
public Builder addUris(@NonNull Collection<String> uris) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
mUris.addAll(uris);
return this;
}
@@ -161,11 +162,11 @@
public Builder addProjection(
@NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemaType);
- Preconditions.checkNotNull(propertyPaths);
+ Objects.requireNonNull(schemaType);
+ Objects.requireNonNull(propertyPaths);
List<String> propertyPathsList = new ArrayList<>(propertyPaths.size());
for (String propertyPath : propertyPaths) {
- Preconditions.checkNotNull(propertyPath);
+ Objects.requireNonNull(propertyPath);
propertyPathsList.add(propertyPath);
}
mProjectionTypePropertyPaths.put(schemaType, propertyPathsList);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
index 1f56ef3..691ef4f 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
@@ -24,6 +24,7 @@
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.Set;
/** The response class of {@link AppSearchSession#getSchema} */
@@ -34,7 +35,7 @@
private final Bundle mBundle;
GetSchemaResponse(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/**
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
index bfb9323..4f63bae 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
@@ -20,7 +20,7 @@
import android.app.appsearch.util.BundleUtil;
import android.os.Bundle;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/** This class represents a uniquely identifiable package. */
public class PackageIdentifier {
@@ -43,7 +43,7 @@
/** @hide */
public PackageIdentifier(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/** @hide */
@@ -54,12 +54,12 @@
@NonNull
public String getPackageName() {
- return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
+ return Objects.requireNonNull(mBundle.getString(PACKAGE_NAME_FIELD));
}
@NonNull
public byte[] getSha256Certificate() {
- return Preconditions.checkNotNull(mBundle.getByteArray(SHA256_CERTIFICATE_FIELD));
+ return Objects.requireNonNull(mBundle.getByteArray(SHA256_CERTIFICATE_FIELD));
}
@Override
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
index 01473be..b49e0e8 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -26,6 +26,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* Encapsulates a request to index documents into an {@link AppSearchSession} database.
@@ -61,7 +62,7 @@
*/
@NonNull
public Builder addGenericDocuments(@NonNull GenericDocument... documents) {
- Preconditions.checkNotNull(documents);
+ Objects.requireNonNull(documents);
return addGenericDocuments(Arrays.asList(documents));
}
@@ -74,7 +75,7 @@
public Builder addGenericDocuments(
@NonNull Collection<? extends GenericDocument> documents) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(documents);
+ Objects.requireNonNull(documents);
mDocuments.addAll(documents);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
index 8da68c0..4dcad68 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
@@ -24,6 +24,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
/**
@@ -65,7 +66,7 @@
/** Creates a {@link RemoveByUriRequest.Builder} instance. */
public Builder(@NonNull String namespace) {
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -75,7 +76,7 @@
*/
@NonNull
public Builder addUris(@NonNull String... uris) {
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
return addUris(Arrays.asList(uris));
}
@@ -87,7 +88,7 @@
@NonNull
public Builder addUris(@NonNull Collection<String> uris) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
mUris.addAll(uris);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
index 2e152f8..8aff3b4 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
@@ -20,6 +20,8 @@
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* A request to report usage of a document owned by another app from a system UI surface.
*
@@ -42,10 +44,10 @@
@NonNull String namespace,
@NonNull String uri,
long usageTimeMillis) {
- mPackageName = Preconditions.checkNotNull(packageName);
- mDatabase = Preconditions.checkNotNull(database);
- mNamespace = Preconditions.checkNotNull(namespace);
- mUri = Preconditions.checkNotNull(uri);
+ mPackageName = Objects.requireNonNull(packageName);
+ mDatabase = Objects.requireNonNull(database);
+ mNamespace = Objects.requireNonNull(namespace);
+ mUri = Objects.requireNonNull(uri);
mUsageTimeMillis = usageTimeMillis;
}
@@ -95,9 +97,9 @@
/** Creates a {@link ReportSystemUsageRequest.Builder} instance. */
public Builder(
@NonNull String packageName, @NonNull String database, @NonNull String namespace) {
- mPackageName = Preconditions.checkNotNull(packageName);
- mDatabase = Preconditions.checkNotNull(database);
- mNamespace = Preconditions.checkNotNull(namespace);
+ mPackageName = Objects.requireNonNull(packageName);
+ mDatabase = Objects.requireNonNull(database);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -110,7 +112,7 @@
@NonNull
public ReportSystemUsageRequest.Builder setUri(@NonNull String uri) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uri);
+ Objects.requireNonNull(uri);
mUri = uri;
return this;
}
@@ -142,7 +144,7 @@
@NonNull
public ReportSystemUsageRequest build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(mUri, "ReportUsageRequest is missing a URI");
+ Objects.requireNonNull(mUri, "ReportUsageRequest is missing a URI");
if (mUsageTimeMillis == null) {
mUsageTimeMillis = System.currentTimeMillis();
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
index 646e73c..925bde9 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
@@ -20,6 +20,8 @@
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* A request to report usage of a document.
*
@@ -33,8 +35,8 @@
private final long mUsageTimeMillis;
ReportUsageRequest(@NonNull String namespace, @NonNull String uri, long usageTimeMillis) {
- mNamespace = Preconditions.checkNotNull(namespace);
- mUri = Preconditions.checkNotNull(uri);
+ mNamespace = Objects.requireNonNull(namespace);
+ mUri = Objects.requireNonNull(uri);
mUsageTimeMillis = usageTimeMillis;
}
@@ -69,7 +71,7 @@
/** Creates a {@link ReportUsageRequest.Builder} instance. */
public Builder(@NonNull String namespace) {
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -82,7 +84,7 @@
@NonNull
public ReportUsageRequest.Builder setUri(@NonNull String uri) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uri);
+ Objects.requireNonNull(uri);
mUri = uri;
return this;
}
@@ -114,7 +116,7 @@
@NonNull
public ReportUsageRequest build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(mUri, "ReportUsageRequest is missing a URI");
+ Objects.requireNonNull(mUri, "ReportUsageRequest is missing a URI");
if (mUsageTimeMillis == null) {
mUsageTimeMillis = System.currentTimeMillis();
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
index 55a228d..432f838 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -59,7 +59,7 @@
/** @hide */
public SearchResult(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/** @hide */
@@ -77,8 +77,7 @@
public GenericDocument getGenericDocument() {
if (mDocument == null) {
mDocument =
- new GenericDocument(
- Preconditions.checkNotNull(mBundle.getBundle(DOCUMENT_FIELD)));
+ new GenericDocument(Objects.requireNonNull(mBundle.getBundle(DOCUMENT_FIELD)));
}
return mDocument;
}
@@ -95,7 +94,7 @@
public List<MatchInfo> getMatches() {
if (mMatches == null) {
List<Bundle> matchBundles =
- Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
+ Objects.requireNonNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
mMatches = new ArrayList<>(matchBundles.size());
for (int i = 0; i < matchBundles.size(); i++) {
MatchInfo matchInfo = new MatchInfo(matchBundles.get(i), getGenericDocument());
@@ -112,7 +111,7 @@
*/
@NonNull
public String getPackageName() {
- return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
+ return Objects.requireNonNull(mBundle.getString(PACKAGE_NAME_FIELD));
}
/**
@@ -122,7 +121,7 @@
*/
@NonNull
public String getDatabaseName() {
- return Preconditions.checkNotNull(mBundle.getString(DATABASE_NAME_FIELD));
+ return Objects.requireNonNull(mBundle.getString(DATABASE_NAME_FIELD));
}
/**
@@ -169,8 +168,8 @@
* @param databaseName the database name the matched document belongs to.
*/
public Builder(@NonNull String packageName, @NonNull String databaseName) {
- mBundle.putString(PACKAGE_NAME_FIELD, Preconditions.checkNotNull(packageName));
- mBundle.putString(DATABASE_NAME_FIELD, Preconditions.checkNotNull(databaseName));
+ mBundle.putString(PACKAGE_NAME_FIELD, Objects.requireNonNull(packageName));
+ mBundle.putString(DATABASE_NAME_FIELD, Objects.requireNonNull(databaseName));
}
/**
@@ -312,9 +311,9 @@
@Nullable private MatchRange mWindowRange;
MatchInfo(@NonNull Bundle bundle, @Nullable GenericDocument document) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
mDocument = document;
- mPropertyPath = Preconditions.checkNotNull(bundle.getString(PROPERTY_PATH_FIELD));
+ mPropertyPath = Objects.requireNonNull(bundle.getString(PROPERTY_PATH_FIELD));
}
/**
@@ -449,7 +448,7 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBundle.putString(
SearchResult.MatchInfo.PROPERTY_PATH_FIELD,
- Preconditions.checkNotNull(propertyPath));
+ Objects.requireNonNull(propertyPath));
return this;
}
@@ -461,7 +460,7 @@
@NonNull
public Builder setExactMatchRange(@NonNull MatchRange matchRange) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(matchRange);
+ Objects.requireNonNull(matchRange);
mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, matchRange.getStart());
mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, matchRange.getEnd());
return this;
@@ -475,7 +474,7 @@
@NonNull
public Builder setSnippetRange(@NonNull MatchRange matchRange) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(matchRange);
+ Objects.requireNonNull(matchRange);
mBundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, matchRange.getStart());
mBundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, matchRange.getEnd());
return this;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
index dbd09d6..4853b5b 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
@@ -20,11 +20,10 @@
import android.annotation.Nullable;
import android.os.Bundle;
-import com.android.internal.util.Preconditions;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* This class represents a page of {@link SearchResult}s
@@ -41,7 +40,7 @@
@NonNull private final Bundle mBundle;
public SearchResultPage(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
mNextPageToken = mBundle.getLong(NEXT_PAGE_TOKEN_FIELD);
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index 19d9430..d466bf1 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -34,6 +34,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -176,7 +177,7 @@
/** @hide */
public SearchSpec(@NonNull Bundle bundle) {
- Preconditions.checkNotNull(bundle);
+ Objects.requireNonNull(bundle);
mBundle = bundle;
}
@@ -342,7 +343,7 @@
*/
@NonNull
public Builder addFilterSchemas(@NonNull String... schemas) {
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
Preconditions.checkState(!mBuilt, "Builder has already been used");
return addFilterSchemas(Arrays.asList(schemas));
}
@@ -355,7 +356,7 @@
*/
@NonNull
public Builder addFilterSchemas(@NonNull Collection<String> schemas) {
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mSchemas.addAll(schemas);
return this;
@@ -369,7 +370,7 @@
*/
@NonNull
public Builder addFilterNamespaces(@NonNull String... namespaces) {
- Preconditions.checkNotNull(namespaces);
+ Objects.requireNonNull(namespaces);
Preconditions.checkState(!mBuilt, "Builder has already been used");
return addFilterNamespaces(Arrays.asList(namespaces));
}
@@ -382,7 +383,7 @@
*/
@NonNull
public Builder addFilterNamespaces(@NonNull Collection<String> namespaces) {
- Preconditions.checkNotNull(namespaces);
+ Objects.requireNonNull(namespaces);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mNamespaces.addAll(namespaces);
return this;
@@ -398,7 +399,7 @@
*/
@NonNull
public Builder addFilterPackageNames(@NonNull String... packageNames) {
- Preconditions.checkNotNull(packageNames);
+ Objects.requireNonNull(packageNames);
Preconditions.checkState(!mBuilt, "Builder has already been used");
return addFilterPackageNames(Arrays.asList(packageNames));
}
@@ -413,7 +414,7 @@
*/
@NonNull
public Builder addFilterPackageNames(@NonNull Collection<String> packageNames) {
- Preconditions.checkNotNull(packageNames);
+ Objects.requireNonNull(packageNames);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mPackageNames.addAll(packageNames);
return this;
@@ -586,11 +587,11 @@
public SearchSpec.Builder addProjection(
@NonNull String schema, @NonNull Collection<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schema);
- Preconditions.checkNotNull(propertyPaths);
+ Objects.requireNonNull(schema);
+ Objects.requireNonNull(propertyPaths);
ArrayList<String> propertyPathsArrayList = new ArrayList<>(propertyPaths.size());
for (String propertyPath : propertyPaths) {
- Preconditions.checkNotNull(propertyPath);
+ Objects.requireNonNull(propertyPath);
propertyPathsArrayList.add(propertyPath);
}
mProjectionTypePropertyMasks.putStringArrayList(schema, propertyPathsArrayList);
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 5672bc7..8f7a0bf 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -28,6 +28,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -94,10 +95,10 @@
@NonNull Map<String, Migrator> migrators,
boolean forceOverride,
int version) {
- mSchemas = Preconditions.checkNotNull(schemas);
- mSchemasNotDisplayedBySystem = Preconditions.checkNotNull(schemasNotDisplayedBySystem);
- mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages);
- mMigrators = Preconditions.checkNotNull(migrators);
+ mSchemas = Objects.requireNonNull(schemas);
+ mSchemasNotDisplayedBySystem = Objects.requireNonNull(schemasNotDisplayedBySystem);
+ mSchemasVisibleToPackages = Objects.requireNonNull(schemasVisibleToPackages);
+ mMigrators = Objects.requireNonNull(migrators);
mForceOverride = forceOverride;
mVersion = version;
}
@@ -192,7 +193,7 @@
*/
@NonNull
public Builder addSchemas(@NonNull AppSearchSchema... schemas) {
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
return addSchemas(Arrays.asList(schemas));
}
@@ -206,7 +207,7 @@
@NonNull
public Builder addSchemas(@NonNull Collection<AppSearchSchema> schemas) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
mSchemas.addAll(schemas);
return this;
}
@@ -231,7 +232,7 @@
@NonNull
public Builder setSchemaTypeDisplayedBySystem(
@NonNull String schemaType, boolean displayed) {
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(schemaType);
Preconditions.checkState(!mBuilt, "Builder has already been used");
if (displayed) {
@@ -270,8 +271,8 @@
@NonNull String schemaType,
boolean visible,
@NonNull PackageIdentifier packageIdentifier) {
- Preconditions.checkNotNull(schemaType);
- Preconditions.checkNotNull(packageIdentifier);
+ Objects.requireNonNull(schemaType);
+ Objects.requireNonNull(packageIdentifier);
Preconditions.checkState(!mBuilt, "Builder has already been used");
Set<PackageIdentifier> packageIdentifiers = mSchemasVisibleToPackages.get(schemaType);
@@ -321,8 +322,8 @@
@NonNull
@SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) {
- Preconditions.checkNotNull(schemaType);
- Preconditions.checkNotNull(migrator);
+ Objects.requireNonNull(schemaType);
+ Objects.requireNonNull(migrator);
mMigrators.put(schemaType, migrator);
return this;
}
@@ -350,7 +351,7 @@
*/
@NonNull
public Builder setMigrators(@NonNull Map<String, Migrator> migrators) {
- Preconditions.checkNotNull(migrators);
+ Objects.requireNonNull(migrators);
mMigrators.putAll(migrators);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
index d63e437..7be589f 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
@@ -27,6 +27,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/** The response class of {@link AppSearchSession#setSchema} */
@@ -61,8 +62,8 @@
@Nullable private Set<String> mIncompatibleTypes;
SetSchemaResponse(@NonNull Bundle bundle, @NonNull List<MigrationFailure> migrationFailures) {
- mBundle = Preconditions.checkNotNull(bundle);
- mMigrationFailures = Preconditions.checkNotNull(migrationFailures);
+ mBundle = Objects.requireNonNull(bundle);
+ mMigrationFailures = Objects.requireNonNull(migrationFailures);
}
SetSchemaResponse(@NonNull Bundle bundle) {
@@ -103,7 +104,7 @@
if (mDeletedTypes == null) {
mDeletedTypes =
new ArraySet<>(
- Preconditions.checkNotNull(
+ Objects.requireNonNull(
mBundle.getStringArrayList(DELETED_TYPES_FIELD)));
}
return Collections.unmodifiableSet(mDeletedTypes);
@@ -118,7 +119,7 @@
if (mMigratedTypes == null) {
mMigratedTypes =
new ArraySet<>(
- Preconditions.checkNotNull(
+ Objects.requireNonNull(
mBundle.getStringArrayList(MIGRATED_TYPES_FIELD)));
}
return Collections.unmodifiableSet(mMigratedTypes);
@@ -139,7 +140,7 @@
if (mIncompatibleTypes == null) {
mIncompatibleTypes =
new ArraySet<>(
- Preconditions.checkNotNull(
+ Objects.requireNonNull(
mBundle.getStringArrayList(INCOMPATIBLE_TYPES_FIELD)));
}
return Collections.unmodifiableSet(mIncompatibleTypes);
@@ -173,7 +174,7 @@
public Builder addMigrationFailures(
@NonNull Collection<MigrationFailure> migrationFailures) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigrationFailures.addAll(Preconditions.checkNotNull(migrationFailures));
+ mMigrationFailures.addAll(Objects.requireNonNull(migrationFailures));
return this;
}
@@ -181,7 +182,7 @@
@NonNull
public Builder addMigrationFailure(@NonNull MigrationFailure migrationFailure) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigrationFailures.add(Preconditions.checkNotNull(migrationFailure));
+ mMigrationFailures.add(Objects.requireNonNull(migrationFailure));
return this;
}
@@ -189,7 +190,7 @@
@NonNull
public Builder addDeletedTypes(@NonNull Collection<String> deletedTypes) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mDeletedTypes.addAll(Preconditions.checkNotNull(deletedTypes));
+ mDeletedTypes.addAll(Objects.requireNonNull(deletedTypes));
return this;
}
@@ -197,7 +198,7 @@
@NonNull
public Builder addDeletedType(@NonNull String deletedType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mDeletedTypes.add(Preconditions.checkNotNull(deletedType));
+ mDeletedTypes.add(Objects.requireNonNull(deletedType));
return this;
}
@@ -205,7 +206,7 @@
@NonNull
public Builder addIncompatibleTypes(@NonNull Collection<String> incompatibleTypes) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mIncompatibleTypes.addAll(Preconditions.checkNotNull(incompatibleTypes));
+ mIncompatibleTypes.addAll(Objects.requireNonNull(incompatibleTypes));
return this;
}
@@ -213,7 +214,7 @@
@NonNull
public Builder addIncompatibleType(@NonNull String incompatibleType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mIncompatibleTypes.add(Preconditions.checkNotNull(incompatibleType));
+ mIncompatibleTypes.add(Objects.requireNonNull(incompatibleType));
return this;
}
@@ -221,7 +222,7 @@
@NonNull
public Builder addMigratedTypes(@NonNull Collection<String> migratedTypes) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigratedTypes.addAll(Preconditions.checkNotNull(migratedTypes));
+ mMigratedTypes.addAll(Objects.requireNonNull(migratedTypes));
return this;
}
@@ -229,7 +230,7 @@
@NonNull
public Builder addMigratedType(@NonNull String migratedType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigratedTypes.add(Preconditions.checkNotNull(migratedType));
+ mMigratedTypes.add(Objects.requireNonNull(migratedType));
return this;
}
@@ -318,7 +319,7 @@
@NonNull
public Builder setSchemaType(@NonNull String schemaType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mSchemaType = Preconditions.checkNotNull(schemaType);
+ mSchemaType = Objects.requireNonNull(schemaType);
return this;
}
@@ -326,7 +327,7 @@
@NonNull
public Builder setNamespace(@NonNull String namespace) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
return this;
}
@@ -334,7 +335,7 @@
@NonNull
public Builder setUri(@NonNull String uri) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mUri = Preconditions.checkNotNull(uri);
+ mUri = Objects.requireNonNull(uri);
return this;
}
@@ -343,7 +344,7 @@
public Builder setAppSearchResult(@NonNull AppSearchResult<Void> appSearchResult) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkState(!appSearchResult.isSuccess(), "Input a success result");
- mFailureResult = Preconditions.checkNotNull(appSearchResult);
+ mFailureResult = Objects.requireNonNull(appSearchResult);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
index dc04cf3..502b939 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
@@ -21,6 +21,8 @@
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/** The response class of {@code AppSearchSession#getStorageInfo}. */
public class StorageInfo {
@@ -31,7 +33,7 @@
private final Bundle mBundle;
StorageInfo(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/**
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
index 32d7e043..10e014b 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
@@ -37,7 +37,11 @@
public final class SchemaMigrationUtil {
private SchemaMigrationUtil() {}
- /** Returns all active {@link Migrator}s that need to be triggered in this migration. */
+ /**
+ * Returns all active {@link Migrator}s that need to be triggered in this migration.
+ *
+ * <p>{@link Migrator#shouldMigrate} returns {@code true} will make the {@link Migrator} active.
+ */
@NonNull
public static Map<String, Migrator> getActiveMigrators(
@NonNull Set<AppSearchSchema> existingSchemas,
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 35c441e..693acf1 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -44,7 +44,6 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
-import android.os.ParcelableException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -63,6 +62,8 @@
import com.android.server.appsearch.stats.LoggerInstanceManager;
import com.android.server.appsearch.stats.PlatformLogger;
+import com.google.android.icing.proto.PersistType;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
@@ -74,7 +75,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
-import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -93,7 +94,7 @@
// mutate requests will need to gain write lock and query requests need to gain read lock.
private static final Executor EXECUTOR = new ThreadPoolExecutor(/*corePoolSize=*/1,
Runtime.getRuntime().availableProcessors(), /*keepAliveTime*/ 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
+ new LinkedBlockingQueue<>());
// Cache of unlocked user ids so we don't have to query UserManager service each time. The
// "locked" suffix refers to the fact that access to the field should be locked; unrelated to
@@ -320,6 +321,8 @@
++operationFailureCount;
}
}
+ // Now that the batch has been written. Persist the newly written data.
+ impl.persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, resultBuilder.build());
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -587,7 +590,7 @@
}
}
}
- impl.persistToDisk();
+ impl.persistToDisk(PersistType.Code.FULL);
invokeCallbackOnResult(callback,
AppSearchResult.newSuccessfulResult(migrationFailureBundles));
} catch (Throwable t) {
@@ -664,6 +667,8 @@
resultBuilder.setResult(uri, throwableToFailedResult(t));
}
}
+ // Now that the batch has been written. Persist the newly written data.
+ impl.persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, resultBuilder.build());
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -697,6 +702,8 @@
databaseName,
queryExpression,
new SearchSpec(searchSpecBundle));
+ // Now that the batch has been written. Persist the newly written data.
+ impl.persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -741,7 +748,7 @@
verifyUserUnlocked(callingUserId);
AppSearchImpl impl =
mImplInstanceManager.getAppSearchImpl(callingUserId);
- impl.persistToDisk();
+ impl.persistToDisk(PersistType.Code.FULL);
} catch (Throwable t) {
Log.e(TAG, "Unable to persist the data to disk", t);
}
@@ -829,13 +836,12 @@
/**
* Invokes the {@link IAppSearchBatchResultCallback} with an unexpected internal throwable.
*
- * <p>The throwable is converted to {@link ParcelableException}.
+ * <p>The throwable is converted to {@link AppSearchResult}.
*/
private void invokeCallbackOnError(
- IAppSearchBatchResultCallback callback, Throwable throwable) {
+ @NonNull IAppSearchBatchResultCallback callback, @NonNull Throwable throwable) {
try {
- //TODO(b/175067650) verify ParcelableException could propagate throwable correctly.
- callback.onSystemError(new ParcelableException(throwable));
+ callback.onSystemError(throwableToFailedResult(throwable));
} catch (RemoteException e) {
Log.e(TAG, "Unable to send error to the callback", e);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
index 1ed26d6..c1b8294 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
@@ -36,6 +36,7 @@
import android.util.Log;
import com.android.internal.util.Preconditions;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import java.util.ArrayList;
import java.util.Arrays;
@@ -153,7 +154,7 @@
* AppSearchImpl.
*/
static final String VISIBILITY_STORE_PREFIX =
- AppSearchImpl.createPrefix(PACKAGE_NAME, DATABASE_NAME);
+ PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
/** Namespace of documents that contain visibility settings */
private static final String NAMESPACE = "";
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 5f8cbee..50ac054 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
@@ -16,10 +16,18 @@
package com.android.server.appsearch.external.localstorage;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.addPrefixToDocument;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPackagePrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getDatabaseName;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPackageName;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefixesFromDocument;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
-import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.GetByUriRequest;
@@ -39,7 +47,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.ResultCodeToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
@@ -66,7 +73,6 @@
import com.google.android.icing.proto.PersistToDiskResultProto;
import com.google.android.icing.proto.PersistType;
import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.PropertyProto;
import com.google.android.icing.proto.PutResultProto;
import com.google.android.icing.proto.ReportUsageResultProto;
import com.google.android.icing.proto.ResetResultProto;
@@ -89,6 +95,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -132,10 +139,6 @@
public final class AppSearchImpl implements Closeable {
private static final String TAG = "AppSearchImpl";
- @VisibleForTesting static final char DATABASE_DELIMITER = '/';
-
- @VisibleForTesting static final char PACKAGE_DELIMITER = '$';
-
@VisibleForTesting static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
@VisibleForTesting static final int OPTIMIZE_THRESHOLD_BYTES = 1_000_000; // 1MB
@VisibleForTesting static final int CHECK_OPTIMIZE_INTERVAL = 100;
@@ -148,11 +151,12 @@
@GuardedBy("mReadWriteLock")
private final VisibilityStore mVisibilityStoreLocked;
- // This map contains schemaTypes for all package-database prefixes. All values in the map are
- // prefixed with the package-database prefix.
- // TODO(b/172360376): Check if this can be replaced with an ArrayMap
+ // This map contains schema types and SchemaTypeConfigProtos for all package-database
+ // prefixes. It maps each package-database prefix to an inner-map. The inner-map maps each
+ // prefixed schema type to its respective SchemaTypeConfigProto.
@GuardedBy("mReadWriteLock")
- private final Map<String, Set<String>> mSchemaMapLocked = new HashMap<>();
+ private final Map<String, Map<String, SchemaTypeConfigProto>> mSchemaMapLocked =
+ new ArrayMap<>();
// This map contains namespaces for all package-database prefixes. All values in the map are
// prefixed with the package-database prefix.
@@ -182,9 +186,9 @@
int userId,
@NonNull String globalQuerierPackage)
throws AppSearchException {
- Preconditions.checkNotNull(icingDir);
- Preconditions.checkNotNull(context);
- Preconditions.checkNotNull(globalQuerierPackage);
+ Objects.requireNonNull(icingDir);
+ Objects.requireNonNull(context);
+ Objects.requireNonNull(globalQuerierPackage);
AppSearchImpl appSearchImpl =
new AppSearchImpl(icingDir, context, userId, globalQuerierPackage);
appSearchImpl.initializeVisibilityStore();
@@ -229,7 +233,7 @@
// Populate schema map
for (SchemaTypeConfigProto schema : schemaProto.getTypesList()) {
String prefixedSchemaType = schema.getSchemaType();
- addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType), prefixedSchemaType);
+ addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType), schema);
}
// Populate namespace map
@@ -278,7 +282,7 @@
return;
}
- persistToDisk();
+ persistToDisk(PersistType.Code.FULL);
mIcingSearchEngineLocked.close();
mClosedLocked = true;
} catch (AppSearchException e) {
@@ -364,7 +368,14 @@
}
// Update derived data structures.
- mSchemaMapLocked.put(prefix, rewrittenSchemaResults.mRewrittenPrefixedTypes);
+ for (SchemaTypeConfigProto schemaTypeConfigProto :
+ rewrittenSchemaResults.mRewrittenPrefixedTypes.values()) {
+ addToMap(mSchemaMapLocked, prefix, schemaTypeConfigProto);
+ }
+
+ for (String schemaType : rewrittenSchemaResults.mDeletedPrefixedTypes) {
+ removeFromMap(mSchemaMapLocked, prefix, schemaType);
+ }
Set<String> prefixedSchemasNotPlatformSurfaceable =
new ArraySet<>(schemasNotPlatformSurfaceable.size());
@@ -586,7 +597,7 @@
mReadWriteLock.readLock().lock();
try {
throwIfClosedLocked();
-
+ String prefix = createPrefix(packageName, databaseName);
List<TypePropertyMask> nonPrefixedPropertyMasks =
TypePropertyPathToProtoConverter.toTypePropertyMaskList(typePropertyPaths);
List<TypePropertyMask> prefixedPropertyMasks =
@@ -597,7 +608,7 @@
String prefixedType =
nonPrefixedType.equals(GetByUriRequest.PROJECTION_SCHEMA_TYPE_WILDCARD)
? nonPrefixedType
- : createPrefix(packageName, databaseName) + nonPrefixedType;
+ : prefix + nonPrefixedType;
prefixedPropertyMasks.add(
typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
}
@@ -607,15 +618,17 @@
.build();
GetResultProto getResultProto =
- mIcingSearchEngineLocked.get(
- createPrefix(packageName, databaseName) + namespace,
- uri,
- getResultSpec);
+ mIcingSearchEngineLocked.get(prefix + namespace, uri, getResultSpec);
checkSuccess(getResultProto.getStatus());
+ // The schema type map cannot be null at this point. It could only be null if no
+ // schema had ever been set for that prefix. Given we have retrieved a document from
+ // the index, we know a schema had to have been set.
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = mSchemaMapLocked.get(prefix);
DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
removePrefixesFromDocument(documentBuilder);
- return GenericDocumentToProtoConverter.toGenericDocument(documentBuilder.build());
+ return GenericDocumentToProtoConverter.toGenericDocument(
+ documentBuilder.build(), prefix, schemaTypeMap);
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -726,7 +739,7 @@
}
} else {
// Client didn't specify certain schemas to search over, check all schemas
- Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
+ Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix).keySet();
if (prefixedSchemas != null) {
for (String prefixedSchema : prefixedSchemas) {
if (packageName.equals(callerPackageName)
@@ -816,7 +829,7 @@
searchSpecBuilder.build(), scoringSpec, resultSpecBuilder.build());
checkSuccess(searchResultProto.getStatus());
- return rewriteSearchResultProto(searchResultProto);
+ return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
}
/**
@@ -838,7 +851,7 @@
SearchResultProto searchResultProto =
mIcingSearchEngineLocked.getNextPage(nextPageToken);
checkSuccess(searchResultProto.getStatus());
- return rewriteSearchResultProto(searchResultProto);
+ return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -1104,22 +1117,31 @@
/**
* Persists all update/delete requests to the disk.
*
- * <p>If the app crashes after a call to PersistToDisk(), Icing would be able to fully recover
- * all data written up to this point without a costly recovery process.
+ * <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#FULL}, Icing
+ * would be able to fully recover all data written up to this point without a costly recovery
+ * process.
*
- * <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly recovery
- * process in next initialization. After that, Icing would still be able to recover all written
- * data.
+ * <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#LITE}, Icing
+ * would trigger a costly recovery process in next initialization. After that, Icing would still
+ * be able to recover all written data - excepting Usage data. Usage data is only guaranteed to
+ * be safe after a call to PersistToDisk with {@link PersistType.Code#FULL}
*
+ * <p>If the app crashes after an update/delete request has been made, but before any call to
+ * PersistToDisk, then all data in Icing will be lost.
+ *
+ * @param persistType the amount of data to persist. {@link PersistType.Code#LITE} will only
+ * persist the minimal amount of data to ensure all data can be recovered. {@link
+ * PersistType.Code#FULL} will persist all data necessary to prevent data loss without
+ * needing data recovery.
* @throws AppSearchException on any error that AppSearch persist data to disk.
*/
- public void persistToDisk() throws AppSearchException {
+ public void persistToDisk(@NonNull PersistType.Code persistType) throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
throwIfClosedLocked();
PersistToDiskResultProto persistToDiskResultProto =
- mIcingSearchEngineLocked.persistToDisk(PersistType.Code.FULL);
+ mIcingSearchEngineLocked.persistToDisk(persistType);
checkSuccess(persistToDiskResultProto.getStatus());
} finally {
mReadWriteLock.writeLock().unlock();
@@ -1189,8 +1211,8 @@
// Any prefixed types that used to exist in the schema, but are deleted in the new one.
final Set<String> mDeletedPrefixedTypes = new ArraySet<>();
- // Prefixed types that were part of the new schema.
- final Set<String> mRewrittenPrefixedTypes = new ArraySet<>();
+ // Map of prefixed schema types to SchemaTypeConfigProtos that were part of the new schema.
+ final Map<String, SchemaTypeConfigProto> mRewrittenPrefixedTypes = new ArrayMap<>();
}
/**
@@ -1238,7 +1260,7 @@
// newTypesToProto is modified below, so we need a copy first
RewrittenSchemaResults rewrittenSchemaResults = new RewrittenSchemaResults();
- rewrittenSchemaResults.mRewrittenPrefixedTypes.addAll(newTypesToProto.keySet());
+ rewrittenSchemaResults.mRewrittenPrefixedTypes.putAll(newTypesToProto);
// Combine the existing schema (which may have types from other prefixes) with this
// prefix's new schema. Modifies the existingSchemaBuilder.
@@ -1264,99 +1286,6 @@
}
/**
- * Prepends {@code prefix} to all types and namespaces mentioned anywhere in {@code
- * documentBuilder}.
- *
- * @param documentBuilder The document to mutate
- * @param prefix The prefix to add
- */
- @VisibleForTesting
- static void addPrefixToDocument(
- @NonNull DocumentProto.Builder documentBuilder, @NonNull String prefix) {
- // Rewrite the type name to include/remove the prefix.
- String newSchema = prefix + documentBuilder.getSchema();
- documentBuilder.setSchema(newSchema);
-
- // Rewrite the namespace to include/remove the prefix.
- documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- addPrefixToDocument(derivedDocumentBuilder, prefix);
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
- }
-
- /**
- * Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
- *
- * @param documentBuilder The document to mutate
- * @return Prefix name that was removed from the document.
- * @throws AppSearchException if there are unexpected database prefixing errors.
- */
- @NonNull
- @VisibleForTesting
- static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
- throws AppSearchException {
- // Rewrite the type name and namespace to remove the prefix.
- String schemaPrefix = getPrefix(documentBuilder.getSchema());
- String namespacePrefix = getPrefix(documentBuilder.getNamespace());
-
- if (!schemaPrefix.equals(namespacePrefix)) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- "Found unexpected"
- + " multiple prefix names in document: "
- + schemaPrefix
- + ", "
- + namespacePrefix);
- }
-
- documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
- documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
- if (!nestedPrefix.equals(schemaPrefix)) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- "Found unexpected multiple prefix names in document: "
- + schemaPrefix
- + ", "
- + nestedPrefix);
- }
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
-
- return schemaPrefix;
- }
-
- /**
* Rewrites the search spec filters with {@code prefixes}.
*
* <p>This method should be only called in query methods and get the READ lock to keep thread
@@ -1443,9 +1372,9 @@
if (allowedPrefixedSchemas.isEmpty()) {
// If the client didn't specify any schema filters, search over all of their schemas
- Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
- if (prefixedSchemas != null) {
- allowedPrefixedSchemas.addAll(prefixedSchemas);
+ Map<String, SchemaTypeConfigProto> prefixedSchemaMap = mSchemaMapLocked.get(prefix);
+ if (prefixedSchemaMap != null) {
+ allowedPrefixedSchemas.addAll(prefixedSchemaMap.keySet());
}
}
return allowedPrefixedSchemas;
@@ -1656,86 +1585,6 @@
return mSchemaMapLocked.keySet();
}
- @NonNull
- static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
- return createPackagePrefix(packageName) + databaseName + DATABASE_DELIMITER;
- }
-
- @NonNull
- private static String createPackagePrefix(@NonNull String packageName) {
- return packageName + PACKAGE_DELIMITER;
- }
-
- /**
- * Returns the package name that's contained within the {@code prefix}.
- *
- * @param prefix Prefix string that contains the package name inside of it. The package name
- * must be in the front of the string, and separated from the rest of the string by the
- * {@link #PACKAGE_DELIMITER}.
- * @return Valid package name.
- */
- @NonNull
- private static String getPackageName(@NonNull String prefix) {
- int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
- if (delimiterIndex == -1) {
- // This should never happen if we construct our prefixes properly
- Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
- return "";
- }
- return prefix.substring(0, delimiterIndex);
- }
-
- /**
- * Returns the database name that's contained within the {@code prefix}.
- *
- * @param prefix Prefix string that contains the database name inside of it. The database name
- * must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
- * @return Valid database name.
- */
- @NonNull
- private static String getDatabaseName(@NonNull String prefix) {
- int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
- int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
- if (packageDelimiterIndex == -1) {
- // This should never happen if we construct our prefixes properly
- Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
- return "";
- }
- if (databaseDelimiterIndex == -1) {
- // This should never happen if we construct our prefixes properly
- Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
- return "";
- }
- return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
- }
-
- @NonNull
- private static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
- // The prefix is made up of the package, then the database. So we only need to find the
- // database cutoff.
- int delimiterIndex;
- if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
- // Add 1 to include the char size of the DATABASE_DELIMITER
- return prefixedString.substring(delimiterIndex + 1);
- }
- throw new AppSearchException(
- AppSearchResult.RESULT_UNKNOWN_ERROR,
- "The prefixed value doesn't contains a valid database name.");
- }
-
- @NonNull
- private static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
- int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
- if (databaseDelimiterIndex == -1) {
- throw new AppSearchException(
- AppSearchResult.RESULT_UNKNOWN_ERROR,
- "The databaseName prefixed value doesn't contain a valid database name.");
- }
-
- // Add 1 to include the char size of the DATABASE_DELIMITER
- return prefixedString.substring(0, databaseDelimiterIndex + 1);
- }
-
private static void addToMap(
Map<String, Set<String>> map, String prefix, String prefixedValue) {
Set<String> values = map.get(prefix);
@@ -1746,6 +1595,26 @@
values.add(prefixedValue);
}
+ private static void addToMap(
+ Map<String, Map<String, SchemaTypeConfigProto>> map,
+ String prefix,
+ SchemaTypeConfigProto schemaTypeConfigProto) {
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
+ if (schemaTypeMap == null) {
+ schemaTypeMap = new ArrayMap<>();
+ map.put(prefix, schemaTypeMap);
+ }
+ schemaTypeMap.put(schemaTypeConfigProto.getSchemaType(), schemaTypeConfigProto);
+ }
+
+ private static void removeFromMap(
+ Map<String, Map<String, SchemaTypeConfigProto>> map, String prefix, String schemaType) {
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
+ if (schemaTypeMap != null) {
+ schemaTypeMap.remove(schemaType);
+ }
+ }
+
/**
* Checks the given status code and throws an {@link AppSearchException} if code is an error.
*
@@ -1853,7 +1722,9 @@
/** Remove the rewritten schema types from any result documents. */
@NonNull
@VisibleForTesting
- static SearchResultPage rewriteSearchResultProto(@NonNull SearchResultProto searchResultProto)
+ static SearchResultPage rewriteSearchResultProto(
+ @NonNull SearchResultProto searchResultProto,
+ @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap)
throws AppSearchException {
// Parallel array of package names for each document search result.
List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());
@@ -1873,7 +1744,7 @@
resultsBuilder.setResults(i, resultBuilder);
}
return SearchResultToProtoConverter.toSearchResultPage(
- resultsBuilder, packageNames, databaseNames);
+ resultsBuilder, packageNames, databaseNames, schemaMap);
}
@GuardedBy("mReadWriteLock")
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
index 5680670..cdd7952 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -18,11 +18,12 @@
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.google.android.icing.proto.PutDocumentStatsProto;
+import java.util.Objects;
+
/**
* Class contains helper functions for logging.
*
@@ -42,8 +43,8 @@
static void copyNativeStats(
@NonNull PutDocumentStatsProto fromNativeStats,
@NonNull PutDocumentStats.Builder toStatsBuilder) {
- Preconditions.checkNotNull(fromNativeStats);
- Preconditions.checkNotNull(toStatsBuilder);
+ Objects.requireNonNull(fromNativeStats);
+ Objects.requireNonNull(toStatsBuilder);
toStatsBuilder
.setNativeLatencyMillis(fromNativeStats.getLatencyMs())
.setNativeDocumentStoreLatencyMillis(fromNativeStats.getDocumentStoreLatencyMs())
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
index d6b9da8..5ff56ab 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
@@ -17,16 +17,18 @@
package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
+import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.protobuf.ByteString;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
/**
* Translates a {@link GenericDocument} into a {@link DocumentProto}.
@@ -34,13 +36,20 @@
* @hide
*/
public final class GenericDocumentToProtoConverter {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final long[] EMPTY_LONG_ARRAY = new long[0];
+ private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+ private static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
+ private static final byte[][] EMPTY_BYTES_ARRAY = new byte[0][0];
+ private static final GenericDocument[] EMPTY_DOCUMENT_ARRAY = new GenericDocument[0];
+
private GenericDocumentToProtoConverter() {}
/** Converts a {@link GenericDocument} into a {@link DocumentProto}. */
@NonNull
@SuppressWarnings("unchecked")
public static DocumentProto toDocumentProto(@NonNull GenericDocument document) {
- Preconditions.checkNotNull(document);
+ Objects.requireNonNull(document);
DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
mProtoBuilder
.setUri(document.getUri())
@@ -97,16 +106,34 @@
return mProtoBuilder.build();
}
- /** Converts a {@link DocumentProto} into a {@link GenericDocument}. */
+ /**
+ * Converts a {@link DocumentProto} into a {@link GenericDocument}.
+ *
+ * <p>In the case that the {@link DocumentProto} object proto has no values set, the converter
+ * searches for the matching property name in the {@link SchemaTypeConfigProto} object for the
+ * document, and infers the correct default value to set for the empty property based on the
+ * data type of the property defined by the schema type.
+ *
+ * @param proto the document to convert to a {@link GenericDocument} instance. The document
+ * proto should have its package + database prefix stripped from its fields.
+ * @param prefix the package + database prefix used searching the {@code schemaTypeMap}.
+ * @param schemaTypeMap map of prefixed schema type to {@link SchemaTypeConfigProto}, used for
+ * looking up the default empty value to set for a document property that has all empty
+ * values.
+ */
@NonNull
- public static GenericDocument toGenericDocument(@NonNull DocumentProto proto) {
- Preconditions.checkNotNull(proto);
+ public static GenericDocument toGenericDocument(
+ @NonNull DocumentProto proto,
+ @NonNull String prefix,
+ @NonNull Map<String, SchemaTypeConfigProto> schemaTypeMap) {
+ Objects.requireNonNull(proto);
GenericDocument.Builder<?> documentBuilder =
new GenericDocument.Builder<>(
proto.getNamespace(), proto.getUri(), proto.getSchema())
.setScore(proto.getScore())
.setTtlMillis(proto.getTtlMs())
.setCreationTimestampMillis(proto.getCreationTimestampMs());
+ String prefixedSchemaType = prefix + proto.getSchema();
for (int i = 0; i < proto.getPropertiesCount(); i++) {
PropertyProto property = proto.getProperties(i);
@@ -144,13 +171,51 @@
} else if (property.getDocumentValuesCount() > 0) {
GenericDocument[] values = new GenericDocument[property.getDocumentValuesCount()];
for (int j = 0; j < values.length; j++) {
- values[j] = toGenericDocument(property.getDocumentValues(j));
+ values[j] =
+ toGenericDocument(property.getDocumentValues(j), prefix, schemaTypeMap);
}
documentBuilder.setPropertyDocument(name, values);
} else {
- throw new IllegalStateException("Unknown type of value: " + name);
+ // TODO(b/184966497): Optimize by caching PropertyConfigProto
+ setEmptyProperty(name, documentBuilder, schemaTypeMap.get(prefixedSchemaType));
}
}
return documentBuilder.build();
}
+
+ private static void setEmptyProperty(
+ @NonNull String propertyName,
+ @NonNull GenericDocument.Builder<?> documentBuilder,
+ @NonNull SchemaTypeConfigProto schema) {
+ @AppSearchSchema.PropertyConfig.DataType int dataType = 0;
+ for (int i = 0; i < schema.getPropertiesCount(); ++i) {
+ if (propertyName.equals(schema.getProperties(i).getPropertyName())) {
+ dataType = schema.getProperties(i).getDataType().getNumber();
+ break;
+ }
+ }
+
+ switch (dataType) {
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
+ documentBuilder.setPropertyString(propertyName, EMPTY_STRING_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_INT64:
+ documentBuilder.setPropertyLong(propertyName, EMPTY_LONG_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
+ documentBuilder.setPropertyDouble(propertyName, EMPTY_DOUBLE_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
+ documentBuilder.setPropertyBoolean(propertyName, EMPTY_BOOLEAN_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
+ documentBuilder.setPropertyBytes(propertyName, EMPTY_BYTES_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
+ documentBuilder.setPropertyDocument(propertyName, EMPTY_DOCUMENT_ARRAY);
+ break;
+ default:
+ throw new IllegalStateException("Unknown type of value: " + propertyName);
+ }
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
index 800b073..e3fa7e0 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
@@ -20,8 +20,6 @@
import android.app.appsearch.AppSearchSchema;
import android.util.Log;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.DocumentIndexingConfig;
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;
@@ -30,6 +28,7 @@
import com.google.android.icing.proto.TermMatchType;
import java.util.List;
+import java.util.Objects;
/**
* Translates an {@link AppSearchSchema} into a {@link SchemaTypeConfigProto}.
@@ -48,7 +47,7 @@
@NonNull
public static SchemaTypeConfigProto toSchemaTypeConfigProto(
@NonNull AppSearchSchema schema, int version) {
- Preconditions.checkNotNull(schema);
+ Objects.requireNonNull(schema);
SchemaTypeConfigProto.Builder protoBuilder =
SchemaTypeConfigProto.newBuilder()
.setSchemaType(schema.getSchemaType())
@@ -64,7 +63,7 @@
@NonNull
private static PropertyConfigProto toPropertyConfigProto(
@NonNull AppSearchSchema.PropertyConfig property) {
- Preconditions.checkNotNull(property);
+ Objects.requireNonNull(property);
PropertyConfigProto.Builder builder =
PropertyConfigProto.newBuilder().setPropertyName(property.getName());
@@ -116,7 +115,7 @@
*/
@NonNull
public static AppSearchSchema toAppSearchSchema(@NonNull SchemaTypeConfigProtoOrBuilder proto) {
- Preconditions.checkNotNull(proto);
+ Objects.requireNonNull(proto);
AppSearchSchema.Builder builder = new AppSearchSchema.Builder(proto.getSchemaType());
List<PropertyConfigProto> properties = proto.getPropertiesList();
for (int i = 0; i < properties.size(); i++) {
@@ -129,7 +128,7 @@
@NonNull
private static AppSearchSchema.PropertyConfig toPropertyConfig(
@NonNull PropertyConfigProto proto) {
- Preconditions.checkNotNull(proto);
+ Objects.requireNonNull(proto);
switch (proto.getDataType()) {
case STRING:
return toStringPropertyConfig(proto);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index bf7e533..57c1590 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -16,6 +16,8 @@
package com.android.server.appsearch.external.localstorage.converter;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
+
import android.annotation.NonNull;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.SearchResult;
@@ -24,6 +26,7 @@
import com.android.internal.util.Preconditions;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchResultProtoOrBuilder;
import com.google.android.icing.proto.SnippetMatchProto;
@@ -31,6 +34,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Translates a {@link SearchResultProto} into {@link SearchResult}s.
@@ -49,13 +53,17 @@
* @param databaseNames A parallel array of database names. The database name at index 'i' of
* this list shold be the database that indexed the document at index 'i' of
* proto.getResults(i).
+ * @param schemaMap A map of prefixes to an inner-map of prefixed schema type to
+ * SchemaTypeConfigProtos, used for setting a default value for results with DocumentProtos
+ * that have empty values.
* @return {@link SearchResultPage} of results.
*/
@NonNull
public static SearchResultPage toSearchResultPage(
@NonNull SearchResultProtoOrBuilder proto,
@NonNull List<String> packageNames,
- @NonNull List<String> databaseNames) {
+ @NonNull List<String> databaseNames,
+ @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap) {
Preconditions.checkArgument(
proto.getResultsCount() == packageNames.size(),
"Size of results does not match the number of package names.");
@@ -63,8 +71,14 @@
bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
for (int i = 0; i < proto.getResultsCount(); i++) {
+ String prefix = createPrefix(packageNames.get(i), databaseNames.get(i));
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = schemaMap.get(prefix);
SearchResult result =
- toSearchResult(proto.getResults(i), packageNames.get(i), databaseNames.get(i));
+ toSearchResult(
+ proto.getResults(i),
+ packageNames.get(i),
+ databaseNames.get(i),
+ schemaTypeMap);
resultBundles.add(result.getBundle());
}
bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
@@ -77,15 +91,21 @@
* @param proto The proto to be converted.
* @param packageName The package name associated with the document in {@code proto}.
* @param databaseName The database name associated with the document in {@code proto}.
+ * @param schemaTypeToProtoMap A map of prefixed schema types to their corresponding
+ * SchemaTypeConfigProto, used for setting a default value for results with DocumentProtos
+ * that have empty values.
* @return A {@link SearchResult} bundle.
*/
@NonNull
private static SearchResult toSearchResult(
@NonNull SearchResultProto.ResultProtoOrBuilder proto,
@NonNull String packageName,
- @NonNull String databaseName) {
+ @NonNull String databaseName,
+ @NonNull Map<String, SchemaTypeConfigProto> schemaTypeToProtoMap) {
+ String prefix = createPrefix(packageName, databaseName);
GenericDocument document =
- GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
+ GenericDocumentToProtoConverter.toGenericDocument(
+ proto.getDocument(), prefix, schemaTypeToProtoMap);
SearchResult.Builder builder =
new SearchResult.Builder(packageName, databaseName)
.setGenericDocument(document)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
index d9e8adb..8f9e9bd 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
@@ -19,13 +19,13 @@
import android.annotation.NonNull;
import android.app.appsearch.SearchSpec;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.ResultSpecProto;
import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.TermMatchType;
+import java.util.Objects;
+
/**
* Translates a {@link SearchSpec} into icing search protos.
*
@@ -37,7 +37,7 @@
/** Extracts {@link SearchSpecProto} information from a {@link SearchSpec}. */
@NonNull
public static SearchSpecProto toSearchSpecProto(@NonNull SearchSpec spec) {
- Preconditions.checkNotNull(spec);
+ Objects.requireNonNull(spec);
SearchSpecProto.Builder protoBuilder =
SearchSpecProto.newBuilder()
.addAllSchemaTypeFilters(spec.getFilterSchemas())
@@ -56,7 +56,7 @@
/** Extracts {@link ResultSpecProto} information from a {@link SearchSpec}. */
@NonNull
public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
- Preconditions.checkNotNull(spec);
+ Objects.requireNonNull(spec);
return ResultSpecProto.newBuilder()
.setNumPerPage(spec.getResultCountPerPage())
.setSnippetSpec(
@@ -73,7 +73,7 @@
/** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */
@NonNull
public static ScoringSpecProto toScoringSpecProto(@NonNull SearchSpec spec) {
- Preconditions.checkNotNull(spec);
+ Objects.requireNonNull(spec);
ScoringSpecProto.Builder protoBuilder = ScoringSpecProto.newBuilder();
@SearchSpec.Order int orderCode = spec.getOrder();
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java
index a0f39ec..ed73593 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java
@@ -19,10 +19,10 @@
import android.annotation.NonNull;
import android.app.appsearch.SetSchemaResponse;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.SetSchemaResultProto;
+import java.util.Objects;
+
/**
* Translates a {@link SetSchemaResultProto} into {@link SetSchemaResponse}.
*
@@ -42,8 +42,8 @@
@NonNull
public static SetSchemaResponse toSetSchemaResponse(
@NonNull SetSchemaResultProto proto, @NonNull String prefix) {
- Preconditions.checkNotNull(proto);
- Preconditions.checkNotNull(prefix);
+ Objects.requireNonNull(proto);
+ Objects.requireNonNull(prefix);
SetSchemaResponse.Builder builder = new SetSchemaResponse.Builder();
for (int i = 0; i < proto.getDeletedSchemaTypesCount(); i++) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
index 6f6dad2..acf04ef 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
@@ -18,13 +18,12 @@
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.TypePropertyMask;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Translates a <code>Map<String, List<String>></code> into <code>List<TypePropertyMask></code>.
@@ -38,7 +37,7 @@
@NonNull
public static List<TypePropertyMask> toTypePropertyMaskList(
@NonNull Map<String, List<String>> typePropertyPaths) {
- Preconditions.checkNotNull(typePropertyPaths);
+ Objects.requireNonNull(typePropertyPaths);
List<TypePropertyMask> typePropertyMasks = new ArrayList<>(typePropertyPaths.size());
for (Map.Entry<String, List<String>> e : typePropertyPaths.entrySet()) {
typePropertyMasks.add(
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
index a724f95..cf640c1 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
@@ -19,10 +19,9 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* A class for setting basic information to log for all function calls.
@@ -75,8 +74,8 @@
private final int mNumOperationsFailed;
CallStats(@NonNull Builder builder) {
- Preconditions.checkNotNull(builder);
- mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
+ Objects.requireNonNull(builder);
+ mGeneralStats = Objects.requireNonNull(builder.mGeneralStatsBuilder).build();
mCallType = builder.mCallType;
mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis;
mNumOperationsSucceeded = builder.mNumOperationsSucceeded;
@@ -140,8 +139,8 @@
/** Builder takes {@link GeneralStats.Builder}. */
public Builder(@NonNull String packageName, @NonNull String database) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(database);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(database);
mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
index 8ce8eda..53c1ee3 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.app.appsearch.AppSearchResult;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/**
* A class for holding general logging information.
@@ -48,9 +48,9 @@
private final int mTotalLatencyMillis;
GeneralStats(@NonNull Builder builder) {
- Preconditions.checkNotNull(builder);
- mPackageName = Preconditions.checkNotNull(builder.mPackageName);
- mDatabase = Preconditions.checkNotNull(builder.mDatabase);
+ Objects.requireNonNull(builder);
+ mPackageName = Objects.requireNonNull(builder.mPackageName);
+ mDatabase = Objects.requireNonNull(builder.mDatabase);
mStatusCode = builder.mStatusCode;
mTotalLatencyMillis = builder.mTotalLatencyMillis;
}
@@ -92,8 +92,8 @@
* @param database name of the database logging stats
*/
public Builder(@NonNull String packageName, @NonNull String database) {
- mPackageName = Preconditions.checkNotNull(packageName);
- mDatabase = Preconditions.checkNotNull(database);
+ mPackageName = Objects.requireNonNull(packageName);
+ mDatabase = Objects.requireNonNull(database);
}
/** Sets status code returned from {@link AppSearchResult#getResultCode()} */
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
index c1f6fb1..d031172 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/**
* A class for holding detailed stats to log for each individual document put by a {@link
@@ -60,8 +60,8 @@
private final boolean mNativeExceededMaxNumTokens;
PutDocumentStats(@NonNull Builder builder) {
- Preconditions.checkNotNull(builder);
- mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
+ Objects.requireNonNull(builder);
+ mGeneralStats = Objects.requireNonNull(builder.mGeneralStatsBuilder).build();
mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis;
mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis;
mNativeLatencyMillis = builder.mNativeLatencyMillis;
@@ -142,8 +142,8 @@
/** Builder takes {@link GeneralStats.Builder}. */
public Builder(@NonNull String packageName, @NonNull String database) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(database);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(database);
mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java
new file mode 100644
index 0000000..9ae9f18
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java
@@ -0,0 +1,229 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
+/**
+ * Provides utility functions for working with package + database prefixes.
+ *
+ * @hide
+ */
+public class PrefixUtil {
+ private static final String TAG = "AppSearchPrefixUtil";
+
+ @VisibleForTesting public static final char DATABASE_DELIMITER = '/';
+
+ @VisibleForTesting public static final char PACKAGE_DELIMITER = '$';
+
+ private PrefixUtil() {}
+
+ /** Creates prefix string for given package name and database name. */
+ @NonNull
+ public static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
+ return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
+ }
+ /** Creates prefix string for given package name. */
+ @NonNull
+ public static String createPackagePrefix(@NonNull String packageName) {
+ return packageName + PACKAGE_DELIMITER;
+ }
+
+ /**
+ * Returns the package name that's contained within the {@code prefix}.
+ *
+ * @param prefix Prefix string that contains the package name inside of it. The package name
+ * must be in the front of the string, and separated from the rest of the string by the
+ * {@link #PACKAGE_DELIMITER}.
+ * @return Valid package name.
+ */
+ @NonNull
+ public static String getPackageName(@NonNull String prefix) {
+ int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
+ if (delimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
+ return "";
+ }
+ return prefix.substring(0, delimiterIndex);
+ }
+
+ /**
+ * Returns the database name that's contained within the {@code prefix}.
+ *
+ * @param prefix Prefix string that contains the database name inside of it. The database name
+ * must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
+ * @return Valid database name.
+ */
+ @NonNull
+ public static String getDatabaseName(@NonNull String prefix) {
+ // TODO (b/184050178) Start database delimiter index search from after package delimiter
+ int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
+ int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
+ if (packageDelimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
+ return "";
+ }
+ if (databaseDelimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
+ return "";
+ }
+ return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
+ }
+
+ /**
+ * Creates a string with the package and database prefix removed from the input string.
+ *
+ * @param prefixedString a string containing a package and database prefix.
+ * @return a string with the package and database prefix removed.
+ * @throws AppSearchException if the prefixed value does not contain a valid database name.
+ */
+ @NonNull
+ public static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
+ // The prefix is made up of the package, then the database. So we only need to find the
+ // database cutoff.
+ int delimiterIndex;
+ if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ return prefixedString.substring(delimiterIndex + 1);
+ }
+ throw new AppSearchException(
+ AppSearchResult.RESULT_UNKNOWN_ERROR,
+ "The prefixed value doesn't contains a valid database name.");
+ }
+
+ /**
+ * Creates a package and database prefix string from the input string.
+ *
+ * @param prefixedString a string containing a package and database prefix.
+ * @return a string with the package and database prefix
+ * @throws AppSearchException if the prefixed value does not contain a valid database name.
+ */
+ @NonNull
+ public static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
+ int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
+ if (databaseDelimiterIndex == -1) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_UNKNOWN_ERROR,
+ "The databaseName prefixed value doesn't contain a valid database name.");
+ }
+
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ return prefixedString.substring(0, databaseDelimiterIndex + 1);
+ }
+
+ /**
+ * Prepends {@code prefix} to all types and namespaces mentioned anywhere in {@code
+ * documentBuilder}.
+ *
+ * @param documentBuilder The document to mutate
+ * @param prefix The prefix to add
+ */
+ public static void addPrefixToDocument(
+ @NonNull DocumentProto.Builder documentBuilder, @NonNull String prefix) {
+ // Rewrite the type name to include/remove the prefix.
+ String newSchema = prefix + documentBuilder.getSchema();
+ documentBuilder.setSchema(newSchema);
+
+ // Rewrite the namespace to include/remove the prefix.
+ documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ addPrefixToDocument(derivedDocumentBuilder, prefix);
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+ }
+
+ /**
+ * Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
+ *
+ * @param documentBuilder The document to mutate
+ * @return Prefix name that was removed from the document.
+ * @throws AppSearchException if there are unexpected database prefixing errors.
+ */
+ @NonNull
+ public static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
+ throws AppSearchException {
+ // Rewrite the type name and namespace to remove the prefix.
+ String schemaPrefix = getPrefix(documentBuilder.getSchema());
+ String namespacePrefix = getPrefix(documentBuilder.getNamespace());
+
+ if (!schemaPrefix.equals(namespacePrefix)) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Found unexpected"
+ + " multiple prefix names in document: "
+ + schemaPrefix
+ + ", "
+ + namespacePrefix);
+ }
+
+ documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
+ documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
+ if (!nestedPrefix.equals(schemaPrefix)) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Found unexpected multiple prefix names in document: "
+ + schemaPrefix
+ + ", "
+ + nestedPrefix);
+ }
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+
+ return schemaPrefix;
+ }
+}
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index e46c147..f99664b 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I925ec12f4901c7759976c344ba3428210aada8ad
+If9d1d770d2327d7d0db7d82acfc54787b5de64bc
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index 2069043..494945d 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -187,9 +187,8 @@
* <p>Removed documents will no longer be surfaced by {@link #search} or {@link #getByUri}
* calls.
*
- * <p><b>NOTE:</b>By default, documents are removed via a soft delete operation. Once the
- * document crosses the count threshold or byte usage threshold, the documents will be removed
- * from disk.
+ * <p>Once the database crosses the document count or byte usage threshold, removed documents
+ * will be deleted from disk.
*
* @param request {@link RemoveByUriRequest} with URIs and namespace to remove from the index.
* @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}. The
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index 113f8fe..6dbbcb5 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -26,8 +26,8 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
+import android.util.IndentingPrintWriter;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
index ca588c5..09260b7 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -37,9 +37,9 @@
import android.util.ArraySet;
import android.util.Base64;
import android.util.DebugUtils;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index 8b12beb..e477156 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -15,6 +15,7 @@
*/
package com.android.server.blob;
+import static android.Manifest.permission.ACCESS_BLOBS_ACROSS_USERS;
import static android.app.blob.XmlTags.ATTR_COMMIT_TIME_MS;
import static android.app.blob.XmlTags.ATTR_DESCRIPTION;
import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME;
@@ -36,6 +37,7 @@
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_COMMIT_TIME;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC;
+import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ALLOW_ACCESS_ACROSS_USERS;
import static com.android.server.blob.BlobStoreConfig.hasLeaseWaitTimeElapsed;
import static com.android.server.blob.BlobStoreUtils.getDescriptionResourceId;
import static com.android.server.blob.BlobStoreUtils.getPackageResources;
@@ -45,15 +47,18 @@
import android.app.blob.BlobHandle;
import android.app.blob.LeaseInfo;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.ResourceId;
import android.content.res.Resources;
import android.os.ParcelFileDescriptor;
import android.os.RevocableFileDescriptor;
import android.os.UserHandle;
+import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsEvent;
@@ -62,7 +67,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.server.blob.BlobStoreManagerService.DumpArgs;
@@ -85,7 +89,6 @@
private final long mBlobId;
private final BlobHandle mBlobHandle;
- private final int mUserId;
@GuardedBy("mMetadataLock")
private final ArraySet<Committer> mCommitters = new ArraySet<>();
@@ -94,24 +97,23 @@
private final ArraySet<Leasee> mLeasees = new ArraySet<>();
/**
- * Contains packageName -> {RevocableFileDescriptors}.
+ * Contains Accessor -> {RevocableFileDescriptors}.
*
* Keep track of RevocableFileDescriptors given to clients which are not yet revoked/closed so
* that when clients access is revoked or the blob gets deleted, we can be sure that clients
* do not have any reference to the blob and the space occupied by the blob can be freed.
*/
@GuardedBy("mRevocableFds")
- private final ArrayMap<String, ArraySet<RevocableFileDescriptor>> mRevocableFds =
+ private final ArrayMap<Accessor, ArraySet<RevocableFileDescriptor>> mRevocableFds =
new ArrayMap<>();
// Do not access this directly, instead use #getBlobFile().
private File mBlobFile;
- BlobMetadata(Context context, long blobId, BlobHandle blobHandle, int userId) {
+ BlobMetadata(Context context, long blobId, BlobHandle blobHandle) {
mContext = context;
this.mBlobId = blobId;
this.mBlobHandle = blobHandle;
- this.mUserId = userId;
}
long getBlobId() {
@@ -122,10 +124,6 @@
return mBlobHandle;
}
- int getUserId() {
- return mUserId;
- }
-
void addOrReplaceCommitter(@NonNull Committer committer) {
synchronized (mMetadataLock) {
// We need to override the committer data, so first remove any existing
@@ -155,13 +153,24 @@
}
}
- void removeCommittersFromUnknownPkgs(SparseArray<String> knownPackages) {
+ void removeCommittersFromUnknownPkgs(SparseArray<SparseArray<String>> knownPackages) {
synchronized (mMetadataLock) {
- mCommitters.removeIf(committer ->
- !committer.packageName.equals(knownPackages.get(committer.uid)));
+ mCommitters.removeIf(committer -> {
+ final int userId = UserHandle.getUserId(committer.uid);
+ final SparseArray<String> userPackages = knownPackages.get(userId);
+ if (userPackages == null) {
+ return true;
+ }
+ return !committer.packageName.equals(userPackages.get(committer.uid));
+ });
}
}
+ void addCommittersAndLeasees(BlobMetadata blobMetadata) {
+ mCommitters.addAll(blobMetadata.mCommitters);
+ mLeasees.addAll(blobMetadata.mLeasees);
+ }
+
@Nullable
Committer getExistingCommitter(@NonNull String packageName, int uid) {
synchronized (mCommitters) {
@@ -201,10 +210,16 @@
}
}
- void removeLeaseesFromUnknownPkgs(SparseArray<String> knownPackages) {
+ void removeLeaseesFromUnknownPkgs(SparseArray<SparseArray<String>> knownPackages) {
synchronized (mMetadataLock) {
- mLeasees.removeIf(leasee ->
- !leasee.packageName.equals(knownPackages.get(leasee.uid)));
+ mLeasees.removeIf(leasee -> {
+ final int userId = UserHandle.getUserId(leasee.uid);
+ final SparseArray<String> userPackages = knownPackages.get(userId);
+ if (userPackages == null) {
+ return true;
+ }
+ return !leasee.packageName.equals(userPackages.get(leasee.uid));
+ });
}
}
@@ -214,6 +229,25 @@
}
}
+ void removeDataForUser(int userId) {
+ synchronized (mMetadataLock) {
+ mCommitters.removeIf(committer -> (userId == UserHandle.getUserId(committer.uid)));
+ mLeasees.removeIf(leasee -> (userId == UserHandle.getUserId(leasee.uid)));
+ mRevocableFds.entrySet().removeIf(entry -> {
+ final Accessor accessor = entry.getKey();
+ final ArraySet<RevocableFileDescriptor> rFds = entry.getValue();
+ if (userId != UserHandle.getUserId(accessor.uid)) {
+ return false;
+ }
+ for (int i = 0, fdCount = rFds.size(); i < fdCount; ++i) {
+ rFds.valueAt(i).revoke();
+ }
+ rFds.clear();
+ return true;
+ });
+ }
+ }
+
boolean hasValidLeases() {
synchronized (mMetadataLock) {
for (int i = 0, size = mLeasees.size(); i < size; ++i) {
@@ -244,8 +278,12 @@
}
}
+ final int callingUserId = UserHandle.getUserId(callingUid);
for (int i = 0, size = mCommitters.size(); i < size; ++i) {
final Committer committer = mCommitters.valueAt(i);
+ if (callingUserId != UserHandle.getUserId(committer.uid)) {
+ continue;
+ }
// Check if the caller is the same package that committed the blob.
if (committer.equals(callingPackage, callingUid)) {
@@ -259,38 +297,105 @@
return true;
}
}
+
+ final boolean canCallerAccessBlobsAcrossUsers = checkCallerCanAccessBlobsAcrossUsers(
+ callingPackage, callingUserId);
+ if (!canCallerAccessBlobsAcrossUsers) {
+ return false;
+ }
+ for (int i = 0, size = mCommitters.size(); i < size; ++i) {
+ final Committer committer = mCommitters.valueAt(i);
+ final int committerUserId = UserHandle.getUserId(committer.uid);
+ if (callingUserId == committerUserId) {
+ continue;
+ }
+ if (!checkCallerCanAccessBlobsAcrossUsers(callingPackage, committerUserId)) {
+ continue;
+ }
+
+ // Check if the caller is allowed access as per the access mode specified
+ // by the committer.
+ if (committer.blobAccessMode.isAccessAllowedForCaller(mContext,
+ callingPackage, committer.packageName, callingUid, attributionTag)) {
+ return true;
+ }
+ }
+
+ }
+ return false;
+ }
+
+ private static boolean checkCallerCanAccessBlobsAcrossUsers(
+ String callingPackage, int callingUserId) {
+ return PermissionManager.checkPackageNamePermission(ACCESS_BLOBS_ACROSS_USERS,
+ callingPackage, callingUserId) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ boolean hasACommitterOrLeaseeInUser(int userId) {
+ return hasACommitterInUser(userId) || hasALeaseeInUser(userId);
+ }
+
+ boolean hasACommitterInUser(int userId) {
+ synchronized (mMetadataLock) {
+ for (int i = 0, size = mCommitters.size(); i < size; ++i) {
+ final Committer committer = mCommitters.valueAt(i);
+ if (userId == UserHandle.getUserId(committer.uid)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean hasALeaseeInUser(int userId) {
+ synchronized (mMetadataLock) {
+ for (int i = 0, size = mLeasees.size(); i < size; ++i) {
+ final Leasee leasee = mLeasees.valueAt(i);
+ if (userId == UserHandle.getUserId(leasee.uid)) {
+ return true;
+ }
+ }
}
return false;
}
boolean isACommitter(@NonNull String packageName, int uid) {
synchronized (mMetadataLock) {
- return isAnAccessor(mCommitters, packageName, uid);
+ return isAnAccessor(mCommitters, packageName, uid, UserHandle.getUserId(uid));
}
}
boolean isALeasee(@Nullable String packageName, int uid) {
synchronized (mMetadataLock) {
- final Leasee leasee = getAccessor(mLeasees, packageName, uid);
+ final Leasee leasee = getAccessor(mLeasees, packageName, uid,
+ UserHandle.getUserId(uid));
+ return leasee != null && leasee.isStillValid();
+ }
+ }
+
+ private boolean isALeaseeInUser(@Nullable String packageName, int uid, int userId) {
+ synchronized (mMetadataLock) {
+ final Leasee leasee = getAccessor(mLeasees, packageName, uid, userId);
return leasee != null && leasee.isStillValid();
}
}
private static <T extends Accessor> boolean isAnAccessor(@NonNull ArraySet<T> accessors,
- @Nullable String packageName, int uid) {
+ @Nullable String packageName, int uid, int userId) {
// Check if the package is an accessor of the data blob.
- return getAccessor(accessors, packageName, uid) != null;
+ return getAccessor(accessors, packageName, uid, userId) != null;
}
private static <T extends Accessor> T getAccessor(@NonNull ArraySet<T> accessors,
- @Nullable String packageName, int uid) {
+ @Nullable String packageName, int uid, int userId) {
// Check if the package is an accessor of the data blob.
for (int i = 0, size = accessors.size(); i < size; ++i) {
final Accessor accessor = accessors.valueAt(i);
if (packageName != null && uid != INVALID_UID
&& accessor.equals(packageName, uid)) {
return (T) accessor;
- } else if (packageName != null && accessor.packageName.equals(packageName)) {
+ } else if (packageName != null && accessor.packageName.equals(packageName)
+ && userId == UserHandle.getUserId(accessor.uid)) {
return (T) accessor;
} else if (uid != INVALID_UID && accessor.uid == uid) {
return (T) accessor;
@@ -299,23 +404,29 @@
return null;
}
- boolean isALeasee(@NonNull String packageName) {
- return isALeasee(packageName, INVALID_UID);
+ boolean shouldAttributeToLeasee(@NonNull String packageName, int userId,
+ boolean callerHasStatsPermission) {
+ if (!isALeaseeInUser(packageName, INVALID_UID, userId)) {
+ return false;
+ }
+ if (!callerHasStatsPermission || !hasOtherLeasees(packageName, INVALID_UID, userId)) {
+ return true;
+ }
+ return false;
}
- boolean isALeasee(int uid) {
- return isALeasee(null, uid);
+ boolean shouldAttributeToLeasee(int uid, boolean callerHasStatsPermission) {
+ final int userId = UserHandle.getUserId(uid);
+ if (!isALeaseeInUser(null, uid, userId)) {
+ return false;
+ }
+ if (!callerHasStatsPermission || !hasOtherLeasees(null, uid, userId)) {
+ return true;
+ }
+ return false;
}
- boolean hasOtherLeasees(@NonNull String packageName) {
- return hasOtherLeasees(packageName, INVALID_UID);
- }
-
- boolean hasOtherLeasees(int uid) {
- return hasOtherLeasees(null, uid);
- }
-
- private boolean hasOtherLeasees(@Nullable String packageName, int uid) {
+ private boolean hasOtherLeasees(@Nullable String packageName, int uid, int userId) {
synchronized (mMetadataLock) {
for (int i = 0, size = mLeasees.size(); i < size; ++i) {
final Leasee leasee = mLeasees.valueAt(i);
@@ -326,7 +437,8 @@
if (packageName != null && uid != INVALID_UID
&& !leasee.equals(packageName, uid)) {
return true;
- } else if (packageName != null && !leasee.packageName.equals(packageName)) {
+ } else if (packageName != null && (!leasee.packageName.equals(packageName)
+ || userId != UserHandle.getUserId(leasee.uid))) {
return true;
} else if (uid != INVALID_UID && leasee.uid != uid) {
return true;
@@ -371,7 +483,7 @@
return mBlobFile;
}
- ParcelFileDescriptor openForRead(String callingPackage) throws IOException {
+ ParcelFileDescriptor openForRead(String callingPackage, int callingUid) throws IOException {
// TODO: Add limit on opened fds
FileDescriptor fd;
try {
@@ -381,7 +493,7 @@
}
try {
if (BlobStoreConfig.shouldUseRevocableFdForReads()) {
- return createRevocableFd(fd, callingPackage);
+ return createRevocableFd(fd, callingPackage, callingUid);
} else {
return new ParcelFileDescriptor(fd);
}
@@ -393,26 +505,28 @@
@NonNull
private ParcelFileDescriptor createRevocableFd(FileDescriptor fd,
- String callingPackage) throws IOException {
+ String callingPackage, int callingUid) throws IOException {
final RevocableFileDescriptor revocableFd =
new RevocableFileDescriptor(mContext, fd);
+ final Accessor accessor;
synchronized (mRevocableFds) {
- ArraySet<RevocableFileDescriptor> revocableFdsForPkg =
- mRevocableFds.get(callingPackage);
- if (revocableFdsForPkg == null) {
- revocableFdsForPkg = new ArraySet<>();
- mRevocableFds.put(callingPackage, revocableFdsForPkg);
+ accessor = new Accessor(callingPackage, callingUid);
+ ArraySet<RevocableFileDescriptor> revocableFdsForAccessor =
+ mRevocableFds.get(accessor);
+ if (revocableFdsForAccessor == null) {
+ revocableFdsForAccessor = new ArraySet<>();
+ mRevocableFds.put(accessor, revocableFdsForAccessor);
}
- revocableFdsForPkg.add(revocableFd);
+ revocableFdsForAccessor.add(revocableFd);
}
revocableFd.addOnCloseListener((e) -> {
synchronized (mRevocableFds) {
- final ArraySet<RevocableFileDescriptor> revocableFdsForPkg =
- mRevocableFds.get(callingPackage);
- if (revocableFdsForPkg != null) {
- revocableFdsForPkg.remove(revocableFd);
- if (revocableFdsForPkg.isEmpty()) {
- mRevocableFds.remove(callingPackage);
+ final ArraySet<RevocableFileDescriptor> revocableFdsForAccessor =
+ mRevocableFds.get(accessor);
+ if (revocableFdsForAccessor != null) {
+ revocableFdsForAccessor.remove(revocableFd);
+ if (revocableFdsForAccessor.isEmpty()) {
+ mRevocableFds.remove(accessor);
}
}
}
@@ -421,22 +535,23 @@
}
void destroy() {
- revokeAllFds();
+ revokeAndClearAllFds();
getBlobFile().delete();
}
- private void revokeAllFds() {
+ private void revokeAndClearAllFds() {
synchronized (mRevocableFds) {
- for (int i = 0, pkgCount = mRevocableFds.size(); i < pkgCount; ++i) {
- final ArraySet<RevocableFileDescriptor> packageFds =
+ for (int i = 0, accessorCount = mRevocableFds.size(); i < accessorCount; ++i) {
+ final ArraySet<RevocableFileDescriptor> rFds =
mRevocableFds.valueAt(i);
- if (packageFds == null) {
+ if (rFds == null) {
continue;
}
- for (int j = 0, fdCount = packageFds.size(); j < fdCount; ++j) {
- packageFds.valueAt(j).revoke();
+ for (int j = 0, fdCount = rFds.size(); j < fdCount; ++j) {
+ rFds.valueAt(j).revoke();
}
}
+ mRevocableFds.clear();
}
}
@@ -547,10 +662,10 @@
fout.println("<empty>");
} else {
for (int i = 0, count = mRevocableFds.size(); i < count; ++i) {
- final String packageName = mRevocableFds.keyAt(i);
- final ArraySet<RevocableFileDescriptor> packageFds =
+ final Accessor accessor = mRevocableFds.keyAt(i);
+ final ArraySet<RevocableFileDescriptor> rFds =
mRevocableFds.valueAt(i);
- fout.println(packageName + "#" + packageFds.size());
+ fout.println(accessor + ": #" + rFds.size());
}
}
fout.decreaseIndent();
@@ -560,7 +675,6 @@
void writeToXml(XmlSerializer out) throws IOException {
synchronized (mMetadataLock) {
XmlUtils.writeLongAttribute(out, ATTR_ID, mBlobId);
- XmlUtils.writeIntAttribute(out, ATTR_USER_ID, mUserId);
out.startTag(null, TAG_BLOB_HANDLE);
mBlobHandle.writeToXml(out);
@@ -584,7 +698,9 @@
static BlobMetadata createFromXml(XmlPullParser in, int version, Context context)
throws XmlPullParserException, IOException {
final long blobId = XmlUtils.readLongAttribute(in, ATTR_ID);
- final int userId = XmlUtils.readIntAttribute(in, ATTR_USER_ID);
+ if (version < XML_VERSION_ALLOW_ACCESS_ACROSS_USERS) {
+ XmlUtils.readIntAttribute(in, ATTR_USER_ID);
+ }
BlobHandle blobHandle = null;
final ArraySet<Committer> committers = new ArraySet<>();
@@ -608,7 +724,7 @@
return null;
}
- final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle, userId);
+ final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle);
blobMetadata.setCommitters(committers);
blobMetadata.setLeasees(leasees);
return blobMetadata;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index 5cebf8d..502b29eb 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -27,12 +27,11 @@
import android.provider.DeviceConfig.Properties;
import android.text.TextUtils;
import android.util.DataUnit;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.TimeUtils;
-import com.android.internal.util.IndentingPrintWriter;
-
import java.io.File;
import java.util.concurrent.TimeUnit;
@@ -47,8 +46,9 @@
public static final int XML_VERSION_ADD_DESC_RES_NAME = 3;
public static final int XML_VERSION_ADD_COMMIT_TIME = 4;
public static final int XML_VERSION_ADD_SESSION_CREATION_TIME = 5;
+ public static final int XML_VERSION_ALLOW_ACCESS_ACROSS_USERS = 6;
- public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_SESSION_CREATION_TIME;
+ public static final int XML_VERSION_CURRENT = XML_VERSION_ALLOW_ACCESS_ACROSS_USERS;
public static final long INVALID_BLOB_ID = 0;
public static final long INVALID_BLOB_SIZE = 0;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 0e73547..cc5e31a 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -32,6 +32,7 @@
import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE;
import static com.android.server.blob.BlobStoreConfig.LOGV;
import static com.android.server.blob.BlobStoreConfig.TAG;
+import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ALLOW_ACCESS_ACROSS_USERS;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT;
import static com.android.server.blob.BlobStoreConfig.getAdjustedCommitTimeMs;
import static com.android.server.blob.BlobStoreConfig.getDeletionOnLastLeaseDelayMs;
@@ -83,6 +84,7 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
+import android.util.IndentingPrintWriter;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -96,7 +98,6 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -129,6 +130,7 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -146,9 +148,9 @@
@GuardedBy("mBlobsLock")
private long mCurrentMaxSessionId;
- // Contains data of userId -> {BlobHandle -> {BlobMetadata}}
+ // Contains data of BlobHandle -> BlobMetadata.
@GuardedBy("mBlobsLock")
- private final SparseArray<ArrayMap<BlobHandle, BlobMetadata>> mBlobsMap = new SparseArray<>();
+ private final ArrayMap<BlobHandle, BlobMetadata> mBlobsMap = new ArrayMap<>();
// Contains all ids that are currently in use.
@GuardedBy("mBlobsLock")
@@ -265,16 +267,6 @@
return userSessions;
}
- @GuardedBy("mBlobsLock")
- private ArrayMap<BlobHandle, BlobMetadata> getUserBlobsLocked(int userId) {
- ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.get(userId);
- if (userBlobs == null) {
- userBlobs = new ArrayMap<>();
- mBlobsMap.put(userId, userBlobs);
- }
- return userBlobs;
- }
-
@VisibleForTesting
void addUserSessionsForTest(LongSparseArray<BlobStoreSession> userSessions, int userId) {
synchronized (mBlobsLock) {
@@ -283,9 +275,16 @@
}
@VisibleForTesting
- void addUserBlobsForTest(ArrayMap<BlobHandle, BlobMetadata> userBlobs, int userId) {
+ BlobMetadata getBlobForTest(BlobHandle blobHandle) {
synchronized (mBlobsLock) {
- mBlobsMap.put(userId, userBlobs);
+ return mBlobsMap.get(blobHandle);
+ }
+ }
+
+ @VisibleForTesting
+ int getBlobsCountForTest() {
+ synchronized (mBlobsLock) {
+ return mBlobsMap.size();
}
}
@@ -319,14 +318,9 @@
}
@GuardedBy("mBlobsLock")
- private void addBlobForUserLocked(BlobMetadata blobMetadata, int userId) {
- addBlobForUserLocked(blobMetadata, getUserBlobsLocked(userId));
- }
-
- @GuardedBy("mBlobsLock")
- private void addBlobForUserLocked(BlobMetadata blobMetadata,
- ArrayMap<BlobHandle, BlobMetadata> userBlobs) {
- userBlobs.put(blobMetadata.getBlobHandle(), blobMetadata);
+ @VisibleForTesting
+ void addBlobLocked(BlobMetadata blobMetadata) {
+ mBlobsMap.put(blobMetadata.getBlobHandle(), blobMetadata);
addActiveBlobIdLocked(blobMetadata.getBlobId());
}
@@ -404,8 +398,7 @@
private ParcelFileDescriptor openBlobInternal(BlobHandle blobHandle, int callingUid,
String callingPackage, String attributionTag) throws IOException {
synchronized (mBlobsLock) {
- final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
- .get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
if (blobMetadata == null) {
@@ -415,7 +408,7 @@
} else {
FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
blobMetadata.getBlobId(), blobMetadata.getSize(),
- FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED);
+ FrameworkStatsLog.BLOB_OPENED__RESULT__ACCESS_NOT_ALLOWED);
}
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
@@ -425,7 +418,7 @@
blobMetadata.getBlobId(), blobMetadata.getSize(),
FrameworkStatsLog.BLOB_OPENED__RESULT__SUCCESS);
- return blobMetadata.openForRead(callingPackage);
+ return blobMetadata.openForRead(callingPackage, callingUid);
}
}
@@ -433,11 +426,11 @@
private int getCommittedBlobsCountLocked(int uid, String packageName) {
// TODO: Maintain a counter instead of traversing all the blobs
final AtomicInteger blobsCount = new AtomicInteger(0);
- forEachBlobInUser((blobMetadata) -> {
+ forEachBlobLocked(blobMetadata -> {
if (blobMetadata.isACommitter(packageName, uid)) {
blobsCount.getAndIncrement();
}
- }, UserHandle.getUserId(uid));
+ });
return blobsCount.get();
}
@@ -445,11 +438,11 @@
private int getLeasedBlobsCountLocked(int uid, String packageName) {
// TODO: Maintain a counter instead of traversing all the blobs
final AtomicInteger blobsCount = new AtomicInteger(0);
- forEachBlobInUser((blobMetadata) -> {
+ forEachBlobLocked(blobMetadata -> {
if (blobMetadata.isALeasee(packageName, uid)) {
blobsCount.getAndIncrement();
}
- }, UserHandle.getUserId(uid));
+ });
return blobsCount.get();
}
@@ -465,8 +458,16 @@
throw new LimitExceededException("Too many leased blobs for the caller: "
+ leasesCount);
}
- final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
- .get(blobHandle);
+ if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0
+ && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
+ FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+ INVALID_BLOB_ID, INVALID_BLOB_SIZE,
+ FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID);
+ throw new IllegalArgumentException(
+ "Lease expiry cannot be later than blobs expiry time");
+ }
+
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
if (blobMetadata == null) {
@@ -481,15 +482,7 @@
throw new SecurityException("Caller not allowed to access " + blobHandle
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
- if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0
- && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
- FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
- blobMetadata.getBlobId(), blobMetadata.getSize(),
- FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID);
- throw new IllegalArgumentException(
- "Lease expiry cannot be later than blobs expiry time");
- }
if (blobMetadata.getSize()
> getRemainingLeaseQuotaBytesInternal(callingUid, callingPackage)) {
@@ -518,20 +511,18 @@
@GuardedBy("mBlobsLock")
long getTotalUsageBytesLocked(int callingUid, String callingPackage) {
final AtomicLong totalBytes = new AtomicLong(0);
- forEachBlobInUser((blobMetadata) -> {
+ forEachBlobLocked((blobMetadata) -> {
if (blobMetadata.isALeasee(callingPackage, callingUid)) {
totalBytes.getAndAdd(blobMetadata.getSize());
}
- }, UserHandle.getUserId(callingUid));
+ });
return totalBytes.get();
}
private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid,
String callingPackage, String attributionTag) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
- getUserBlobsLocked(UserHandle.getUserId(callingUid));
- final BlobMetadata blobMetadata = userBlobs.get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
throw new SecurityException("Caller not allowed to access " + blobHandle
@@ -547,12 +538,12 @@
synchronized (mBlobsLock) {
// Check if blobMetadata object is still valid. If it is not, then
// it means that it was already deleted and nothing else to do here.
- if (!Objects.equals(userBlobs.get(blobHandle), blobMetadata)) {
+ if (!Objects.equals(mBlobsMap.get(blobHandle), blobMetadata)) {
return;
}
if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
deleteBlobLocked(blobMetadata);
- userBlobs.remove(blobHandle);
+ mBlobsMap.remove(blobHandle);
}
writeBlobsInfoAsync();
}
@@ -583,12 +574,18 @@
}
return packageResources;
};
- getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> {
+ forEachBlobLocked((blobHandle, blobMetadata) -> {
+ if (!blobMetadata.hasACommitterOrLeaseeInUser(userId)) {
+ return;
+ }
final ArrayList<LeaseInfo> leaseInfos = new ArrayList<>();
blobMetadata.forEachLeasee(leasee -> {
if (!leasee.isStillValid()) {
return;
}
+ if (userId != UserHandle.getUserId(leasee.uid)) {
+ return;
+ }
final int descriptionResId = leasee.descriptionResEntryName == null
? Resources.ID_NULL
: getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
@@ -608,9 +605,7 @@
private void deleteBlobInternal(long blobId, int callingUid) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(
- UserHandle.getUserId(callingUid));
- userBlobs.entrySet().removeIf(entry -> {
+ mBlobsMap.entrySet().removeIf(entry -> {
final BlobMetadata blobMetadata = entry.getValue();
if (blobMetadata.getBlobId() == blobId) {
deleteBlobLocked(blobMetadata);
@@ -625,19 +620,20 @@
private List<BlobHandle> getLeasedBlobsInternal(int callingUid,
@NonNull String callingPackage) {
final ArrayList<BlobHandle> leasedBlobs = new ArrayList<>();
- forEachBlobInUser(blobMetadata -> {
- if (blobMetadata.isALeasee(callingPackage, callingUid)) {
- leasedBlobs.add(blobMetadata.getBlobHandle());
- }
- }, UserHandle.getUserId(callingUid));
+ synchronized (mBlobsLock) {
+ forEachBlobLocked(blobMetadata -> {
+ if (blobMetadata.isALeasee(callingPackage, callingUid)) {
+ leasedBlobs.add(blobMetadata.getBlobHandle());
+ }
+ });
+ }
return leasedBlobs;
}
private LeaseInfo getLeaseInfoInternal(BlobHandle blobHandle,
int callingUid, @NonNull String callingPackage, String attributionTag) {
synchronized (mBlobsLock) {
- final BlobMetadata blobMetadata = getUserBlobsLocked(UserHandle.getUserId(callingUid))
- .get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
callingPackage, callingUid, attributionTag)) {
throw new SecurityException("Caller not allowed to access " + blobHandle
@@ -699,14 +695,14 @@
FrameworkStatsLog.BLOB_COMMITTED__RESULT__COUNT_LIMIT_EXCEEDED);
break;
}
- final int userId = UserHandle.getUserId(session.getOwnerUid());
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(
- userId);
- BlobMetadata blob = userBlobs.get(session.getBlobHandle());
- if (blob == null) {
+ final BlobMetadata blob;
+ final int blobIndex = mBlobsMap.indexOfKey(session.getBlobHandle());
+ if (blobIndex >= 0) {
+ blob = mBlobsMap.valueAt(blobIndex);
+ } else {
blob = new BlobMetadata(mContext, session.getSessionId(),
- session.getBlobHandle(), userId);
- addBlobForUserLocked(blob, userBlobs);
+ session.getBlobHandle());
+ addBlobLocked(blob);
}
final Committer existingCommitter = blob.getExistingCommitter(
session.getOwnerPackageName(), session.getOwnerUid());
@@ -738,7 +734,7 @@
// But if it is a recommit, just leave it as is.
if (session.getSessionId() == blob.getBlobId()) {
deleteBlobLocked(blob);
- userBlobs.remove(blob.getBlobHandle());
+ mBlobsMap.remove(blob.getBlobHandle());
}
}
// Delete redundant data from recommits.
@@ -874,13 +870,10 @@
out.startTag(null, TAG_BLOBS);
XmlUtils.writeIntAttribute(out, ATTR_VERSION, XML_VERSION_CURRENT);
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- out.startTag(null, TAG_BLOB);
- userBlobs.valueAt(j).writeToXml(out);
- out.endTag(null, TAG_BLOB);
- }
+ for (int i = 0, count = mBlobsMap.size(); i < count; ++i) {
+ out.startTag(null, TAG_BLOB);
+ mBlobsMap.valueAt(i).writeToXml(out);
+ out.endTag(null, TAG_BLOB);
}
out.endTag(null, TAG_BLOBS);
@@ -925,16 +918,21 @@
if (TAG_BLOB.equals(in.getName())) {
final BlobMetadata blobMetadata = BlobMetadata.createFromXml(
in, version, mContext);
- final SparseArray<String> userPackages = allPackages.get(
- blobMetadata.getUserId());
- if (userPackages == null) {
- blobMetadata.getBlobFile().delete();
- } else {
- addBlobForUserLocked(blobMetadata, blobMetadata.getUserId());
- blobMetadata.removeCommittersFromUnknownPkgs(userPackages);
- blobMetadata.removeLeaseesFromUnknownPkgs(userPackages);
- }
+ blobMetadata.removeCommittersFromUnknownPkgs(allPackages);
+ blobMetadata.removeLeaseesFromUnknownPkgs(allPackages);
mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, blobMetadata.getBlobId());
+ if (version >= XML_VERSION_ALLOW_ACCESS_ACROSS_USERS) {
+ addBlobLocked(blobMetadata);
+ } else {
+ final BlobMetadata existingBlobMetadata = mBlobsMap.get(
+ blobMetadata.getBlobHandle());
+ if (existingBlobMetadata == null) {
+ addBlobLocked(blobMetadata);
+ } else {
+ existingBlobMetadata.addCommittersAndLeasees(blobMetadata);
+ blobMetadata.getBlobFile().delete();
+ }
+ }
}
}
if (LOGV) {
@@ -977,14 +975,6 @@
}
}
- private int getPackageUid(String packageName, int userId) {
- final int uid = mPackageManagerInternal.getPackageUid(
- packageName,
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES,
- userId);
- return uid;
- }
-
private SparseArray<SparseArray<String>> getAllPackages() {
final SparseArray<SparseArray<String>> allPackages = new SparseArray<>();
final int[] allUsers = LocalServices.getService(UserManagerInternal.class).getUserIds();
@@ -1004,7 +994,7 @@
return allPackages;
}
- AtomicFile prepareSessionsIndexFile() {
+ private AtomicFile prepareSessionsIndexFile() {
final File file = BlobStoreConfig.prepareSessionIndexFile();
if (file == null) {
return null;
@@ -1012,7 +1002,7 @@
return new AtomicFile(file, "session_index" /* commitLogTag */);
}
- AtomicFile prepareBlobsIndexFile() {
+ private AtomicFile prepareBlobsIndexFile() {
final File file = BlobStoreConfig.prepareBlobsIndexFile();
if (file == null) {
return null;
@@ -1037,9 +1027,7 @@
writeBlobSessionsAsync();
// Remove the package from the committer and leasee list
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
- getUserBlobsLocked(UserHandle.getUserId(uid));
- userBlobs.entrySet().removeIf(entry -> {
+ mBlobsMap.entrySet().removeIf(entry -> {
final BlobMetadata blobMetadata = entry.getValue();
final boolean isACommitter = blobMetadata.isACommitter(packageName, uid);
if (isACommitter) {
@@ -1074,14 +1062,15 @@
}
}
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
- mBlobsMap.removeReturnOld(userId);
- if (userBlobs != null) {
- for (int i = 0, count = userBlobs.size(); i < count; ++i) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(i);
+ mBlobsMap.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
+ blobMetadata.removeDataForUser(userId);
+ if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
deleteBlobLocked(blobMetadata);
+ return true;
}
- }
+ return false;
+ });
if (LOGV) {
Slog.v(TAG, "Removed blobs data in user " + userId);
}
@@ -1114,22 +1103,19 @@
}
// Cleanup any stale blobs.
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- userBlobs.entrySet().removeIf(entry -> {
- final BlobMetadata blobMetadata = entry.getValue();
+ mBlobsMap.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
- // Remove expired leases
- blobMetadata.removeExpiredLeases();
+ // Remove expired leases
+ blobMetadata.removeExpiredLeases();
- if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
- deleteBlobLocked(blobMetadata);
- deletedBlobIds.add(blobMetadata.getBlobId());
- return true;
- }
- return false;
- });
- }
+ if (blobMetadata.shouldBeDeleted(true /* respectLeaseWaitTime */)) {
+ deleteBlobLocked(blobMetadata);
+ deletedBlobIds.add(blobMetadata.getBlobId());
+ return true;
+ }
+ return false;
+ });
writeBlobsInfoAsync();
// Cleanup any stale sessions.
@@ -1195,34 +1181,34 @@
void runClearAllBlobs(@UserIdInt int userId) {
synchronized (mBlobsLock) {
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final int blobUserId = mBlobsMap.keyAt(i);
- if (userId != UserHandle.USER_ALL && userId != blobUserId) {
- continue;
+ mBlobsMap.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
+ if (userId == UserHandle.USER_ALL) {
+ mActiveBlobIds.remove(blobMetadata.getBlobId());
+ return true;
}
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- mActiveBlobIds.remove(userBlobs.valueAt(j).getBlobId());
+ blobMetadata.removeDataForUser(userId);
+ if (blobMetadata.shouldBeDeleted(false /* respectLeaseWaitTime */)) {
+ mActiveBlobIds.remove(blobMetadata.getBlobId());
+ return true;
}
- }
- if (userId == UserHandle.USER_ALL) {
- mBlobsMap.clear();
- } else {
- mBlobsMap.remove(userId);
- }
+ return false;
+ });
writeBlobsInfoAsync();
}
}
void deleteBlob(@NonNull BlobHandle blobHandle, @UserIdInt int userId) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- final BlobMetadata blobMetadata = userBlobs.get(blobHandle);
+ final BlobMetadata blobMetadata = mBlobsMap.get(blobHandle);
if (blobMetadata == null) {
return;
}
- deleteBlobLocked(blobMetadata);
- userBlobs.remove(blobHandle);
+ blobMetadata.removeDataForUser(userId);
+ if (blobMetadata.shouldBeDeleted(false /* respectLeaseWaitTime */)) {
+ deleteBlobLocked(blobMetadata);
+ mBlobsMap.remove(blobHandle);
+ }
writeBlobsInfoAsync();
}
}
@@ -1235,11 +1221,12 @@
boolean isBlobAvailable(long blobId, int userId) {
synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- for (BlobMetadata blobMetadata : userBlobs.values()) {
- if (blobMetadata.getBlobId() == blobId) {
- return true;
+ for (int i = 0, blobCount = mBlobsMap.size(); i < blobCount; ++i) {
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(i);
+ if (blobMetadata.getBlobId() != blobId) {
+ continue;
}
+ return blobMetadata.hasACommitterInUser(userId);
}
return false;
}
@@ -1274,27 +1261,22 @@
@GuardedBy("mBlobsLock")
private void dumpBlobsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final int userId = mBlobsMap.keyAt(i);
- if (!dumpArgs.shouldDumpUser(userId)) {
+ fout.println("List of blobs (" + mBlobsMap.size() + "):");
+ fout.increaseIndent();
+ for (int i = 0, blobCount = mBlobsMap.size(); i < blobCount; ++i) {
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(i);
+ if (!dumpArgs.shouldDumpBlob(blobMetadata.getBlobId())) {
continue;
}
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- fout.println("List of blobs in user #"
- + userId + " (" + userBlobs.size() + "):");
+ fout.println("Blob #" + blobMetadata.getBlobId());
fout.increaseIndent();
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(j);
- if (!dumpArgs.shouldDumpBlob(blobMetadata.getBlobId())) {
- continue;
- }
- fout.println("Blob #" + blobMetadata.getBlobId());
- fout.increaseIndent();
- blobMetadata.dump(fout, dumpArgs);
- fout.decreaseIndent();
- }
+ blobMetadata.dump(fout, dumpArgs);
fout.decreaseIndent();
}
+ if (mBlobsMap.isEmpty()) {
+ fout.println("<empty>");
+ }
+ fout.decreaseIndent();
}
private class BlobStorageStatsAugmenter implements StorageStatsAugmenter {
@@ -1308,13 +1290,12 @@
}
}, userId);
- forEachBlobInUser(blobMetadata -> {
- if (blobMetadata.isALeasee(packageName)) {
- if (!blobMetadata.hasOtherLeasees(packageName) || !callerHasStatsPermission) {
- blobsDataSize.getAndAdd(blobMetadata.getSize());
- }
+ forEachBlob(blobMetadata -> {
+ if (blobMetadata.shouldAttributeToLeasee(packageName, userId,
+ callerHasStatsPermission)) {
+ blobsDataSize.getAndAdd(blobMetadata.getSize());
}
- }, userId);
+ });
stats.dataSize += blobsDataSize.get();
}
@@ -1330,13 +1311,12 @@
}
}, userId);
- forEachBlobInUser(blobMetadata -> {
- if (blobMetadata.isALeasee(uid)) {
- if (!blobMetadata.hasOtherLeasees(uid) || !callerHasStatsPermission) {
- blobsDataSize.getAndAdd(blobMetadata.getSize());
- }
+ forEachBlob(blobMetadata -> {
+ if (blobMetadata.shouldAttributeToLeasee(uid,
+ callerHasStatsPermission)) {
+ blobsDataSize.getAndAdd(blobMetadata.getSize());
}
- }, userId);
+ });
stats.dataSize += blobsDataSize.get();
}
@@ -1352,13 +1332,26 @@
}
}
- private void forEachBlobInUser(Consumer<BlobMetadata> consumer, int userId) {
- synchronized (mBlobsLock) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- for (int i = 0, count = userBlobs.size(); i < count; ++i) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(i);
- consumer.accept(blobMetadata);
- }
+ private void forEachBlob(Consumer<BlobMetadata> consumer) {
+ synchronized (mBlobsMap) {
+ forEachBlobLocked(consumer);
+ }
+ }
+
+ @GuardedBy("mBlobsMap")
+ private void forEachBlobLocked(Consumer<BlobMetadata> consumer) {
+ for (int blobIdx = 0, count = mBlobsMap.size(); blobIdx < count; ++blobIdx) {
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(blobIdx);
+ consumer.accept(blobMetadata);
+ }
+ }
+
+ @GuardedBy("mBlobsMap")
+ private void forEachBlobLocked(BiConsumer<BlobHandle, BlobMetadata> consumer) {
+ for (int blobIdx = 0, count = mBlobsMap.size(); blobIdx < count; ++blobIdx) {
+ final BlobHandle blobHandle = mBlobsMap.keyAt(blobIdx);
+ final BlobMetadata blobMetadata = mBlobsMap.valueAt(blobIdx);
+ consumer.accept(blobHandle, blobMetadata);
}
}
@@ -1886,15 +1879,7 @@
}
private int pullBlobData(int atomTag, List<StatsEvent> data) {
- synchronized (mBlobsLock) {
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- final BlobMetadata blob = userBlobs.valueAt(j);
- data.add(blob.dumpAsStatsEvent(atomTag));
- }
- }
- }
+ forEachBlob(blobMetadata -> data.add(blobMetadata.dumpAsStatsEvent(atomTag)));
return StatsManager.PULL_SUCCESS;
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 2c3f682..3f0032f 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -56,12 +56,12 @@
import android.system.ErrnoException;
import android.system.Os;
import android.util.ExceptionUtils;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.blob.BlobStoreManagerService.DumpArgs;
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 88f3df8..9ea6f79 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -208,10 +208,10 @@
public static final int FLAG_PRIORITIZE = 1 << 6;
/**
- * For apps targeting {@link Build.VERSION_CODES#S} or above, APIs
- * {@link #setExactAndAllowWhileIdle(int, long, PendingIntent)} and
- * {@link #setAlarmClock(AlarmClockInfo, PendingIntent)} will require holding a new
- * permission {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}
+ * For apps targeting {@link Build.VERSION_CODES#S} or above, any APIs setting exact alarms,
+ * e.g. {@link #setExact(int, long, PendingIntent)},
+ * {@link #setAlarmClock(AlarmClockInfo, PendingIntent)} and others will require holding a new
+ * permission {@link Manifest.permission#SCHEDULE_EXACT_ALARM}
*
* @hide
*/
@@ -219,6 +219,21 @@
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
public static final long REQUIRE_EXACT_ALARM_PERMISSION = 171306433L;
+ /**
+ * For apps targeting {@link Build.VERSION_CODES#S} or above, all inexact alarms will require
+ * to have a minimum window size, expected to be on the order of a few minutes.
+ *
+ * Practically, any alarms requiring smaller windows are the same as exact alarms and should use
+ * the corresponding APIs provided, like {@link #setExact(int, long, PendingIntent)}, et al.
+ *
+ * Inexact alarm with shorter windows specified will have their windows elongated by the system.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ public static final long ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS = 185199076L;
+
@UnsupportedAppUsage
private final IAlarmManager mService;
private final Context mContext;
@@ -483,6 +498,11 @@
* modest timeliness requirements for its alarms.
*
* <p>
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, the system will ensure that the window
+ * specified is at least a few minutes, as smaller windows are considered practically exact
+ * and should use the other APIs provided for exact alarms.
+ *
+ * <p>
* This method can also be used to achieve strict ordering guarantees among
* multiple alarms by ensuring that the windows requested for each alarm do
* not intersect.
@@ -532,6 +552,13 @@
* The OnAlarmListener {@link OnAlarmListener#onAlarm() onAlarm()} method will be
* invoked via the specified target Handler, or on the application's main looper
* if {@code null} is passed as the {@code targetHandler} parameter.
+ *
+ * <p>
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, the system will ensure that the window
+ * specified is at least a few minutes, as smaller windows are considered practically exact
+ * and should use the other APIs provided for exact alarms.
+ *
+ * @see #setWindow(int, long, long, PendingIntent)
*/
public void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
String tag, OnAlarmListener listener, Handler targetHandler) {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 7a36141..31da201 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -452,7 +452,8 @@
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * INTERVAL_DAY;
- private static final long DEFAULT_MIN_WINDOW = 10_000;
+ // TODO (b/185199076): Tune based on breakage reports.
+ private static final long DEFAULT_MIN_WINDOW = 30 * 60 * 1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10 * 1000;
private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
@@ -1688,12 +1689,22 @@
windowLength = AlarmManager.WINDOW_EXACT;
}
- // Sanity check the window length. This will catch people mistakenly
- // trying to pass an end-of-window timestamp rather than a duration.
- if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
+ // Snap the window to reasonable limits.
+ if (windowLength > INTERVAL_DAY) {
Slog.w(TAG, "Window length " + windowLength
- + "ms suspiciously long; limiting to 1 hour");
- windowLength = AlarmManager.INTERVAL_HOUR;
+ + "ms suspiciously long; limiting to 1 day");
+ windowLength = INTERVAL_DAY;
+ } else if (windowLength > 0 && windowLength < mConstants.MIN_WINDOW) {
+ if (CompatChanges.isChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS,
+ callingPackage, UserHandle.getUserHandleForUid(callingUid))) {
+ Slog.w(TAG, "Window length " + windowLength + "ms too short; expanding to "
+ + mConstants.MIN_WINDOW + "ms.");
+ windowLength = mConstants.MIN_WINDOW;
+ } else {
+ // TODO (b/185199076): Remove log once we have some data about what apps will break
+ Slog.wtf(TAG, "Short window " + windowLength + "ms specified by "
+ + callingPackage);
+ }
}
// Sanity check the recurrence interval. This will catch people who supply
@@ -1737,7 +1748,6 @@
// Fix this window in place, so that as time approaches we don't collapse it.
windowLength = maxElapsed - triggerElapsed;
} else {
- windowLength = Math.max(windowLength, mConstants.MIN_WINDOW);
maxElapsed = triggerElapsed + windowLength;
}
synchronized (mLock) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index d94d638..131783f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -16,6 +16,7 @@
package com.android.server.job;
+import static com.android.server.job.JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.annotation.IntDef;
@@ -39,7 +40,9 @@
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Pair;
+import android.util.Pools;
import android.util.Slog;
+import android.util.SparseArrayMap;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
@@ -60,6 +63,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Iterator;
import java.util.List;
+import java.util.function.Consumer;
/**
* This class decides, given the various configuration and the system status, which jobs can start
@@ -73,6 +77,12 @@
private static final String KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS =
CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms";
private static final long DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS = 30_000;
+ private static final String KEY_PKG_CONCURRENCY_LIMIT_EJ =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "pkg_concurrency_limit_ej";
+ private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_EJ = 3;
+ private static final String KEY_PKG_CONCURRENCY_LIMIT_REGULAR =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "pkg_concurrency_limit_regular";
+ private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = MAX_JOB_CONTEXTS_COUNT / 2;
/**
* Set of possible execution types that a job can have. The actual type(s) of a job are based
@@ -165,8 +175,6 @@
private long mLastScreenOnRealtime;
private long mLastScreenOffRealtime;
- private static final int MAX_JOB_CONTEXTS_COUNT = JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
-
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_ON =
new WorkConfigLimitsPerMemoryTrimLevel(
new WorkTypeConfig("screen_on_normal", 11,
@@ -274,11 +282,28 @@
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
+ private final Pools.Pool<PackageStats> mPkgStatsPool =
+ new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT);
+
+ private final SparseArrayMap<String, PackageStats> mActivePkgStats = new SparseArrayMap<>();
+
private WorkTypeConfig mWorkTypeConfig = CONFIG_LIMITS_SCREEN_OFF.normal;
/** Wait for this long after screen off before adjusting the job concurrency. */
private long mScreenOffAdjustmentDelayMs = DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS;
+ /**
+ * The maximum number of expedited jobs a single userId-package can have running simultaneously.
+ * TOP apps are not limited.
+ */
+ private long mPkgConcurrencyLimitEj = DEFAULT_PKG_CONCURRENCY_LIMIT_EJ;
+
+ /**
+ * The maximum number of regular jobs a single userId-package can have running simultaneously.
+ * TOP apps are not limited.
+ */
+ private long mPkgConcurrencyLimitRegular = DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR;
+
/** Current memory trim level. */
private int mLastMemoryTrimLevel;
@@ -286,6 +311,9 @@
private long mNextSystemStateRefreshTime;
private static final int SYSTEM_STATE_REFRESH_MIN_INTERVAL = 1000;
+ private final Consumer<PackageStats> mPackageStatsStagingCountClearer =
+ PackageStats::resetStagedCount;
+
private final StatLogger mStatLogger = new StatLogger(new String[]{
"assignJobsToContexts",
"refreshSystemState",
@@ -330,6 +358,21 @@
onInteractiveStateChanged(mPowerManager.isInteractive());
}
+ @GuardedBy("mLock")
+ void onAppRemovedLocked(String pkgName, int uid) {
+ final PackageStats packageStats = mActivePkgStats.get(UserHandle.getUserId(uid), pkgName);
+ if (packageStats != null) {
+ if (packageStats.numRunningEj > 0 || packageStats.numRunningRegular > 0) {
+ // Don't delete the object just yet. We'll remove it in onJobCompleted() when the
+ // jobs officially stop running.
+ Slog.w(TAG,
+ pkgName + "(" + uid + ") marked as removed before jobs stopped running");
+ } else {
+ mActivePkgStats.delete(UserHandle.getUserId(uid), pkgName);
+ }
+ }
+ }
+
void onUserRemoved(int userId) {
mGracePeriodObserver.onUserRemoved(userId);
}
@@ -557,6 +600,7 @@
boolean startingJob = false;
int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
String preemptReason = null;
+ final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
// TODO(141645789): rewrite this to look at empty contexts first so we don't
// unnecessarily preempt
for (int j = 0; j < MAX_JOB_CONTEXTS_COUNT; j++) {
@@ -566,7 +610,7 @@
final boolean preferredUidOkay = (preferredUid == nextPending.getUid())
|| (preferredUid == JobServiceContext.NO_PREFERRED_UID);
- if (preferredUidOkay && workType != WORK_TYPE_NONE) {
+ if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) {
// This slot is free, and we haven't yet hit the limit on
// concurrent jobs... we can just throw the job in to here.
selectedContextId = j;
@@ -579,9 +623,11 @@
continue;
}
if (job.getUid() != nextPending.getUid()) {
- // Maybe stop the job if it has had its day in the sun.
+ // Maybe stop the job if it has had its day in the sun. Don't let a different
+ // app preempt jobs started for TOP apps though.
final String reason = shouldStopJobReason[j];
- if (reason != null && mWorkCountTracker.canJobStart(allWorkTypes,
+ if (job.lastEvaluatedPriority < JobInfo.PRIORITY_TOP_APP
+ && reason != null && mWorkCountTracker.canJobStart(allWorkTypes,
activeServices.get(j).getRunningJobWorkType()) != WORK_TYPE_NONE) {
// Right now, the way the code is set up, we don't need to explicitly
// assign the new job to this context since we'll reassign when the
@@ -608,23 +654,27 @@
// actually starting a job, so don't set startingJob.
}
}
+ final PackageStats packageStats = getPkgStatsLocked(
+ nextPending.getSourceUserId(), nextPending.getSourcePackageName());
if (selectedContextId != -1) {
contextIdToJobMap[selectedContextId] = nextPending;
slotChanged[selectedContextId] = true;
preemptReasonCodeForContext[selectedContextId] = preemptReasonCode;
preemptReasonForContext[selectedContextId] = preemptReason;
+ packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob());
}
if (startingJob) {
// Increase the counters when we're going to start a job.
workTypeForContext[selectedContextId] = workType;
mWorkCountTracker.stageJob(workType, allWorkTypes);
+ mActivePkgStats.add(
+ nextPending.getSourceUserId(), nextPending.getSourcePackageName(),
+ packageStats);
}
}
if (DEBUG) {
Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
- }
- if (DEBUG) {
Slog.d(TAG, "assignJobsToContexts: " + mWorkCountTracker.toString());
}
@@ -660,6 +710,7 @@
}
}
mWorkCountTracker.resetStagingCount();
+ mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
noteConcurrency();
}
@@ -702,18 +753,66 @@
}
@GuardedBy("mLock")
+ @NonNull
+ private PackageStats getPkgStatsLocked(int userId, @NonNull String packageName) {
+ PackageStats packageStats = mActivePkgStats.get(userId, packageName);
+ if (packageStats == null) {
+ packageStats = mPkgStatsPool.acquire();
+ if (packageStats == null) {
+ packageStats = new PackageStats();
+ }
+ packageStats.setPackage(userId, packageName);
+ }
+ return packageStats;
+ }
+
+ @GuardedBy("mLock")
+ private boolean isPkgConcurrencyLimitedLocked(@NonNull JobStatus jobStatus) {
+ if (jobStatus.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+ // Don't restrict top apps' concurrency. The work type limits will make sure
+ // background jobs have slots to run if the system has resources.
+ return false;
+ }
+ // Use < instead of <= as that gives us a little wiggle room in case a new job comes
+ // along very shortly.
+ if (mService.mPendingJobs.size() + mRunningJobs.size() < mWorkTypeConfig.getMaxTotal()) {
+ // Don't artificially limit a single package if we don't even have enough jobs to use
+ // the maximum number of slots. We'll preempt the job later if we need the slot.
+ return false;
+ }
+ final PackageStats packageStats =
+ mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+ if (packageStats == null) {
+ // No currently running jobs.
+ return false;
+ }
+ if (jobStatus.shouldTreatAsExpeditedJob()) {
+ return packageStats.numRunningEj + packageStats.numStagedEj < mPkgConcurrencyLimitEj;
+ } else {
+ return packageStats.numRunningRegular + packageStats.numStagedRegular
+ < mPkgConcurrencyLimitRegular;
+ }
+ }
+
+ @GuardedBy("mLock")
private void startJobLocked(@NonNull JobServiceContext worker, @NonNull JobStatus jobStatus,
@WorkType final int workType) {
final List<StateController> controllers = mService.mControllers;
for (int ic = 0; ic < controllers.size(); ic++) {
controllers.get(ic).prepareForExecutionLocked(jobStatus);
}
+ final PackageStats packageStats =
+ getPkgStatsLocked(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+ packageStats.adjustStagedCount(false, jobStatus.shouldTreatAsExpeditedJob());
if (!worker.executeRunnableJob(jobStatus, workType)) {
Slog.e(TAG, "Error executing " + jobStatus);
mWorkCountTracker.onStagedJobFailed(workType);
} else {
mRunningJobs.add(jobStatus);
mWorkCountTracker.onJobStarted(workType);
+ packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob());
+ mActivePkgStats.add(
+ jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), packageStats);
}
final List<JobStatus> pendingJobs = mService.mPendingJobs;
if (pendingJobs.remove(jobStatus)) {
@@ -726,6 +825,18 @@
@WorkType final int workType) {
mWorkCountTracker.onJobFinished(workType);
mRunningJobs.remove(jobStatus);
+ final PackageStats packageStats =
+ mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+ if (packageStats == null) {
+ Slog.wtf(TAG, "Running job didn't have an active PackageStats object");
+ } else {
+ packageStats.adjustRunningCount(false, jobStatus.startedAsExpeditedJob);
+ if (packageStats.numRunningEj <= 0 && packageStats.numRunningRegular <= 0) {
+ mActivePkgStats.delete(packageStats.userId, packageStats.packageName);
+ mPkgStatsPool.release(packageStats);
+ }
+ }
+
final List<JobStatus> pendingJobs = mService.mPendingJobs;
if (worker.getPreferredUid() != JobServiceContext.NO_PREFERRED_UID) {
updateCounterConfigLocked();
@@ -746,7 +857,7 @@
}
if (worker.getPreferredUid() != nextPending.getUid()) {
- if (backupJob == null) {
+ if (backupJob == null && !isPkgConcurrencyLimitedLocked(nextPending)) {
int allWorkTypes = getJobWorkTypes(nextPending);
int workAsType = mWorkCountTracker.canJobStart(allWorkTypes);
if (workAsType != WORK_TYPE_NONE) {
@@ -758,6 +869,13 @@
continue;
}
+ // Only bypass the concurrent limit if we had preempted the job due to a higher
+ // priority job.
+ if (nextPending.lastEvaluatedPriority <= jobStatus.lastEvaluatedPriority
+ && isPkgConcurrencyLimitedLocked(nextPending)) {
+ continue;
+ }
+
if (highestPriorityJob == null
|| highestPriorityJob.lastEvaluatedPriority
< nextPending.lastEvaluatedPriority) {
@@ -815,6 +933,10 @@
continue;
}
+ if (isPkgConcurrencyLimitedLocked(nextPending)) {
+ continue;
+ }
+
final int allWorkTypes = getJobWorkTypes(nextPending);
final int workAsType = mWorkCountTracker.canJobStart(allWorkTypes);
if (workAsType == WORK_TYPE_NONE) {
@@ -979,8 +1101,16 @@
CONFIG_LIMITS_SCREEN_OFF.moderate.update(properties);
CONFIG_LIMITS_SCREEN_OFF.low.update(properties);
CONFIG_LIMITS_SCREEN_OFF.critical.update(properties);
+
+ // Package concurrency limits must in the range [1, MAX_JOB_CONTEXTS_COUNT].
+ mPkgConcurrencyLimitEj = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
+ properties.getInt(KEY_PKG_CONCURRENCY_LIMIT_EJ, DEFAULT_PKG_CONCURRENCY_LIMIT_EJ)));
+ mPkgConcurrencyLimitRegular = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
+ properties.getInt(
+ KEY_PKG_CONCURRENCY_LIMIT_REGULAR, DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR)));
}
+ @GuardedBy("mLock")
public void dumpLocked(IndentingPrintWriter pw, long now, long nowRealtime) {
pw.println("Concurrency:");
@@ -989,6 +1119,8 @@
pw.println("Configuration:");
pw.increaseIndent();
pw.print(KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS, mScreenOffAdjustmentDelayMs).println();
+ pw.print(KEY_PKG_CONCURRENCY_LIMIT_EJ, mPkgConcurrencyLimitEj).println();
+ pw.print(KEY_PKG_CONCURRENCY_LIMIT_REGULAR, mPkgConcurrencyLimitRegular).println();
pw.println();
CONFIG_LIMITS_SCREEN_ON.normal.dump(pw);
pw.println();
@@ -1033,6 +1165,12 @@
pw.println(mLastMemoryTrimLevel);
pw.println();
+ pw.println("Active Package stats:");
+ pw.increaseIndent();
+ mActivePkgStats.forEach(pkgStats -> pkgStats.dumpLocked(pw));
+ pw.decreaseIndent();
+ pw.println();
+
pw.print("User Grace Period: ");
pw.println(mGracePeriodObserver.mGracePeriodExpiration);
pw.println();
@@ -1620,4 +1758,53 @@
return sb.toString();
}
}
+
+ private static class PackageStats {
+ public int userId;
+ public String packageName;
+ public int numRunningEj;
+ public int numRunningRegular;
+ public int numStagedEj;
+ public int numStagedRegular;
+
+ private void setPackage(int userId, @NonNull String packageName) {
+ this.userId = userId;
+ this.packageName = packageName;
+ numRunningEj = numRunningRegular = 0;
+ resetStagedCount();
+ }
+
+ private void resetStagedCount() {
+ numStagedEj = numStagedRegular = 0;
+ }
+
+ private void adjustRunningCount(boolean add, boolean forEj) {
+ if (forEj) {
+ numRunningEj = Math.max(0, numRunningEj + (add ? 1 : -1));
+ } else {
+ numRunningRegular = Math.max(0, numRunningRegular + (add ? 1 : -1));
+ }
+ }
+
+ private void adjustStagedCount(boolean add, boolean forEj) {
+ if (forEj) {
+ numStagedEj = Math.max(0, numStagedEj + (add ? 1 : -1));
+ } else {
+ numStagedRegular = Math.max(0, numStagedRegular + (add ? 1 : -1));
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void dumpLocked(IndentingPrintWriter pw) {
+ pw.print("PackageStats{");
+ pw.print(userId);
+ pw.print("-");
+ pw.print(packageName);
+ pw.print("#runEJ", numRunningEj);
+ pw.print("#runReg", numRunningRegular);
+ pw.print("#stagedEJ", numStagedEj);
+ pw.print("#stagedReg", numStagedRegular);
+ pw.println("}");
+ }
+ }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 8b9eca6..667f5ab 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -21,6 +21,7 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
@@ -67,15 +68,18 @@
import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.SparseSetArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
@@ -316,6 +320,9 @@
*/
final ArrayMap<String, Boolean> mDebuggableApps = new ArrayMap<>();
+ /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
+ private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
+
/**
* Named indices into standby bucket arrays, for clarity in referring to
* specific buckets' bookkeeping.
@@ -785,12 +792,20 @@
} else {
Slog.w(TAG, "PACKAGE_CHANGED for " + pkgName + " / uid " + pkgUid);
}
+ } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ synchronized (mLock) {
+ mUidToPackageCache.remove(uid);
+ }
+ }
} else if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
if (DEBUG) {
Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
}
synchronized (mLock) {
+ mUidToPackageCache.remove(uidRemoved);
// There's no guarantee that the process has been stopped by the time we
// get here, but since this is generally a user-initiated action, it should
// be fine to just put USER instead of UNINSTALL or DISABLED.
@@ -801,6 +816,7 @@
mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid);
}
mDebuggableApps.remove(pkgName);
+ mConcurrencyManager.onAppRemovedLocked(pkgName, pkgUid);
}
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -815,6 +831,7 @@
Slog.d(TAG, "Removing jobs for user: " + userId);
}
synchronized (mLock) {
+ mUidToPackageCache.clear();
cancelJobsForUserLocked(userId);
for (int c = 0; c < mControllers.size(); ++c) {
mControllers.get(c).onUserRemovedLocked(userId);
@@ -904,6 +921,27 @@
return WorkSource.isChainedBatteryAttributionEnabled(getContext());
}
+ @Nullable
+ @GuardedBy("mLock")
+ public ArraySet<String> getPackagesForUidLocked(final int uid) {
+ ArraySet<String> packages = mUidToPackageCache.get(uid);
+ if (packages == null) {
+ try {
+ String[] pkgs = AppGlobals.getPackageManager()
+ .getPackagesForUid(uid);
+ if (pkgs != null) {
+ for (String pkg : pkgs) {
+ mUidToPackageCache.add(uid, pkg);
+ }
+ packages = mUidToPackageCache.get(uid);
+ }
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ }
+ }
+ return packages;
+ }
+
@Override
public void onUserUnlocked(@NonNull TargetUser user) {
synchronized (mLock) {
@@ -1484,6 +1522,7 @@
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
@@ -3285,6 +3324,26 @@
pw.decreaseIndent();
}
+ boolean uidMapPrinted = false;
+ for (int i = 0; i < mUidToPackageCache.size(); ++i) {
+ final int uid = mUidToPackageCache.keyAt(i);
+ if (filterUid != -1 && filterUid != uid) {
+ continue;
+ }
+ if (!uidMapPrinted) {
+ uidMapPrinted = true;
+ pw.println();
+ pw.println("Cached UID->package map:");
+ pw.increaseIndent();
+ }
+ pw.print(uid);
+ pw.print(": ");
+ pw.println(mUidToPackageCache.get(uid));
+ }
+ if (uidMapPrinted) {
+ pw.decreaseIndent();
+ }
+
boolean backingPrinted = false;
for (int i = 0; i < mBackingUpUids.size(); i++) {
int uid = mBackingUpUids.keyAt(i);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 081163b..500735b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -83,6 +83,7 @@
* instance.
*/
private static final long MIN_STATS_UPDATE_INTERVAL_MS = 30_000L;
+ private static final long MIN_ADJUST_CALLBACK_INTERVAL_MS = 1_000L;
private static final int UNBYPASSABLE_BG_BLOCKED_REASONS =
~ConnectivityManager.BLOCKED_REASON_NONE;
@@ -210,6 +211,7 @@
* is only done in {@link #maybeAdjustRegisteredCallbacksLocked()} and may sometimes be stale.
*/
private final List<UidStats> mSortedStats = new ArrayList<>();
+ private long mLastCallbackAdjustmentTimeElapsed;
private static final int MSG_ADJUST_CALLBACKS = 0;
@@ -479,11 +481,15 @@
@GuardedBy("mLock")
@Override
public void onAppRemovedLocked(String pkgName, int uid) {
- mTrackedJobs.delete(uid);
- UidStats uidStats = mUidStats.removeReturnOld(uid);
- unregisterDefaultNetworkCallbackLocked(uid, sElapsedRealtimeClock.millis());
- mSortedStats.remove(uidStats);
- registerPendingUidCallbacksLocked();
+ if (mService.getPackagesForUidLocked(uid) == null) {
+ // All packages in the UID have been removed. It's safe to remove things based on
+ // UID alone.
+ mTrackedJobs.delete(uid);
+ UidStats uidStats = mUidStats.removeReturnOld(uid);
+ unregisterDefaultNetworkCallbackLocked(uid, sElapsedRealtimeClock.millis());
+ mSortedStats.remove(uidStats);
+ registerPendingUidCallbacksLocked();
+ }
}
@GuardedBy("mLock")
@@ -689,7 +695,11 @@
}
private void postAdjustCallbacks() {
- mHandler.obtainMessage(MSG_ADJUST_CALLBACKS).sendToTarget();
+ postAdjustCallbacks(0);
+ }
+
+ private void postAdjustCallbacks(long delayMs) {
+ mHandler.sendEmptyMessageDelayed(MSG_ADJUST_CALLBACKS, delayMs);
}
@GuardedBy("mLock")
@@ -704,6 +714,12 @@
}
final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (nowElapsed - mLastCallbackAdjustmentTimeElapsed < MIN_ADJUST_CALLBACK_INTERVAL_MS) {
+ postAdjustCallbacks(MIN_ADJUST_CALLBACK_INTERVAL_MS);
+ return;
+ }
+
+ mLastCallbackAdjustmentTimeElapsed = nowElapsed;
mSortedStats.clear();
for (int u = 0; u < mUidStats.size(); ++u) {
@@ -725,17 +741,23 @@
for (int j = 0; j < jobs.size(); ++j) {
JobStatus job = jobs.valueAt(j);
- us.earliestEnqueueTime = Math.min(us.earliestEnqueueTime, job.enqueueTime);
if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_CONNECTIVITY)) {
us.numReadyWithConnectivity++;
if (isNetworkAvailable(job)) {
us.numRequestedNetworkAvailable++;
}
+ // Only use the enqueue time of jobs that would be ready to prevent apps
+ // from gaming the system (eg. by scheduling a job that requires all
+ // constraints and has a minimum latency of 6 months to always have the
+ // earliest enqueue time).
+ us.earliestEnqueueTime = Math.min(us.earliestEnqueueTime, job.enqueueTime);
+ if (job.shouldTreatAsExpeditedJob() || job.startedAsExpeditedJob) {
+ us.earliestEJEnqueueTime =
+ Math.min(us.earliestEJEnqueueTime, job.enqueueTime);
+ }
}
if (job.shouldTreatAsExpeditedJob() || job.startedAsExpeditedJob) {
us.numEJs++;
- us.earliestEJEnqueueTime =
- Math.min(us.earliestEJEnqueueTime, job.enqueueTime);
} else {
us.numRegular++;
}
@@ -916,7 +938,10 @@
UidDefaultNetworkCallback defaultNetworkCallback =
mCurrentDefaultNetworkCallbacks.get(jobs.valueAt(0).getSourceUid());
if (defaultNetworkCallback == null) {
- maybeRegisterDefaultNetworkCallbackLocked(jobs.valueAt(0));
+ // This method is only called via a network callback object. That means something
+ // changed about a general network characteristic (since we wouldn't be in this
+ // situation if called from a UID_specific callback). The general network callback
+ // will handle adjusting the per-UID callbacks, so nothing left to do here.
return false;
}
@@ -1096,8 +1121,13 @@
synchronized (mLock) {
if (Objects.equals(mDefaultNetwork, network)) {
mDefaultNetwork = null;
+ updateTrackedJobsLocked(mUid, network);
+ // Add a delay in case onAvailable()+onBlockedStatusChanged is called for a
+ // new network. If this onLost was called because the network is completely
+ // gone, the delay will hel make sure we don't have a short burst of adjusting
+ // callback calls.
+ postAdjustCallbacks(1000);
}
- updateTrackedJobsLocked(mUid, network);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 158a0b9..d4ce437 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -340,9 +340,6 @@
/** List of UIDs currently in the foreground. */
private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
- /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
- private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
-
/**
* List of jobs that started while the UID was in the TOP state. There will be no more than
* 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
@@ -449,22 +446,6 @@
}
}
- private final BroadcastReceiver mPackageAddedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
- if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- return;
- }
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- synchronized (mLock) {
- mUidToPackageCache.remove(uid);
- }
- }
- };
-
/**
* The rolling window size for each standby bucket. Within each window, an app will have 10
* minutes to run its jobs.
@@ -611,9 +592,6 @@
mBackgroundJobsController = backgroundJobsController;
mConnectivityController = connectivityController;
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
-
// Set up the app standby bucketing tracker
AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
appStandby.addListener(new StandbyTracker());
@@ -730,13 +708,15 @@
return;
}
clearAppStatsLocked(UserHandle.getUserId(uid), packageName);
- mForegroundUids.delete(uid);
- mUidToPackageCache.remove(uid);
- mTempAllowlistCache.delete(uid);
- mTempAllowlistGraceCache.delete(uid);
- mTopAppCache.delete(uid);
- mTopAppTrackers.delete(uid);
- mTopAppGraceCache.delete(uid);
+ if (mService.getPackagesForUidLocked(uid) == null) {
+ // All packages in the UID have been removed. It's safe to remove things based on
+ // UID alone.
+ mForegroundUids.delete(uid);
+ mTempAllowlistCache.delete(uid);
+ mTempAllowlistGraceCache.delete(uid);
+ mTopAppCache.delete(uid);
+ mTopAppGraceCache.delete(uid);
+ }
}
@Override
@@ -754,8 +734,8 @@
mInQuotaAlarmListener.removeAlarmsLocked(userId);
mExecutionStatsCache.delete(userId);
mEJStats.delete(userId);
- mUidToPackageCache.clear();
mSystemInstallers.remove(userId);
+ mTopAppTrackers.delete(userId);
}
/** Drop all historical stats and stop tracking any active sessions for the specified app. */
@@ -780,6 +760,7 @@
mInQuotaAlarmListener.removeAlarmLocked(userId, packageName);
mExecutionStatsCache.delete(userId, packageName);
mEJStats.delete(userId, packageName);
+ mTopAppTrackers.delete(userId, packageName);
}
private void cacheInstallerPackagesLocked(int userId) {
@@ -2450,7 +2431,7 @@
synchronized (mLock) {
final long nowElapsed = sElapsedRealtimeClock.millis();
mTempAllowlistCache.put(uid, true);
- final ArraySet<String> packages = getPackagesForUidLocked(uid);
+ final ArraySet<String> packages = mService.getPackagesForUidLocked(uid);
if (packages != null) {
final int userId = UserHandle.getUserId(uid);
for (int i = packages.size() - 1; i >= 0; --i) {
@@ -2505,26 +2486,6 @@
// getRemainingEJExecutionTimeLocked().
}
- @Nullable
- private ArraySet<String> getPackagesForUidLocked(final int uid) {
- ArraySet<String> packages = mUidToPackageCache.get(uid);
- if (packages == null) {
- try {
- String[] pkgs = AppGlobals.getPackageManager()
- .getPackagesForUid(uid);
- if (pkgs != null) {
- for (String pkg : pkgs) {
- mUidToPackageCache.add(uid, pkg);
- }
- packages = mUidToPackageCache.get(uid);
- }
- } catch (RemoteException e) {
- // Shouldn't happen.
- }
- }
- return packages;
- }
-
private class QcHandler extends Handler {
QcHandler(Looper looper) {
@@ -2655,7 +2616,8 @@
// Update Timers first.
if (mPkgTimers.indexOfKey(userId) >= 0
|| mEJPkgTimers.indexOfKey(userId) >= 0) {
- final ArraySet<String> packages = getPackagesForUidLocked(uid);
+ final ArraySet<String> packages =
+ mService.getPackagesForUidLocked(uid);
if (packages != null) {
for (int i = packages.size() - 1; i >= 0; --i) {
Timer t = mEJPkgTimers.get(userId, packages.valueAt(i));
@@ -2740,7 +2702,7 @@
}
mTempAllowlistGraceCache.delete(uid);
mTopAppGraceCache.delete(uid);
- final ArraySet<String> packages = getPackagesForUidLocked(uid);
+ final ArraySet<String> packages = mService.getPackagesForUidLocked(uid);
if (packages != null) {
final int userId = UserHandle.getUserId(uid);
for (int i = packages.size() - 1; i >= 0; --i) {
@@ -4109,17 +4071,6 @@
pw.println(mTempAllowlistGraceCache.toString());
pw.println();
- pw.println("Cached UID->package map:");
- pw.increaseIndent();
- for (int i = 0; i < mUidToPackageCache.size(); ++i) {
- final int uid = mUidToPackageCache.keyAt(i);
- pw.print(uid);
- pw.print(": ");
- pw.println(mUidToPackageCache.get(uid));
- }
- pw.decreaseIndent();
- pw.println();
-
pw.println("Special apps:");
pw.increaseIndent();
pw.print("System installers", mSystemInstallers.toString());
@@ -4278,22 +4229,6 @@
mForegroundUids.keyAt(i));
}
- for (int i = 0; i < mUidToPackageCache.size(); ++i) {
- final long upToken = proto.start(
- StateControllerProto.QuotaController.UID_TO_PACKAGE_CACHE);
-
- final int uid = mUidToPackageCache.keyAt(i);
- ArraySet<String> packages = mUidToPackageCache.get(uid);
-
- proto.write(StateControllerProto.QuotaController.UidPackageMapping.UID, uid);
- for (int j = 0; j < packages.size(); ++j) {
- proto.write(StateControllerProto.QuotaController.UidPackageMapping.PACKAGE_NAMES,
- packages.valueAt(j));
- }
-
- proto.end(upToken);
- }
-
mTrackedJobs.forEach((jobs) -> {
for (int j = 0; j < jobs.size(); j++) {
final JobStatus js = jobs.valueAt(j);
diff --git a/boot/hiddenapi/OWNERS b/boot/hiddenapi/OWNERS
index 5d869fc..74a3dc0 100644
--- a/boot/hiddenapi/OWNERS
+++ b/boot/hiddenapi/OWNERS
@@ -1,7 +1,5 @@
# compat-team@ for changes to hiddenapi files
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+file:tools/platform-compat:/OWNERS
# Escalations:
per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index 6823f65..0420714 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5666,6 +5666,7 @@
field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
field public static final String EXTRA_CALL_PERSON = "android.callPerson";
field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
@@ -5972,6 +5973,7 @@
method @NonNull public static android.app.Notification.CallStyle forScreeningCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent, @NonNull android.app.PendingIntent);
method @NonNull public android.app.Notification.CallStyle setAnswerButtonColorHint(@ColorInt int);
method @NonNull public android.app.Notification.CallStyle setDeclineButtonColorHint(@ColorInt int);
+ method @NonNull public android.app.Notification.CallStyle setIsVideo(boolean);
method @NonNull public android.app.Notification.CallStyle setVerificationIcon(@Nullable android.graphics.drawable.Icon);
method @NonNull public android.app.Notification.CallStyle setVerificationText(@Nullable CharSequence);
}
@@ -7130,7 +7132,7 @@
method public int getGlobalPrivateDnsMode(@NonNull android.content.ComponentName);
method @NonNull public java.util.List<byte[]> getInstalledCaCerts(@Nullable android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getKeepUninstalledPackages(@Nullable android.content.ComponentName);
- method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getKeyPairGrants(@NonNull String);
+ method @NonNull public java.util.Map<java.lang.Integer,java.util.Set<java.lang.String>> getKeyPairGrants(@NonNull String);
method public int getKeyguardDisabledFeatures(@Nullable android.content.ComponentName);
method public int getLockTaskFeatures(@NonNull android.content.ComponentName);
method @NonNull public String[] getLockTaskPackages(@NonNull android.content.ComponentName);
@@ -8602,37 +8604,37 @@
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
method public void finalize();
- method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
field public static final int STATE_NOT_PLAYING = 11; // 0xb
field public static final int STATE_PLAYING = 10; // 0xa
}
public final class BluetoothAdapter {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelDiscovery();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean cancelDiscovery();
method public static boolean checkBluetoothAddress(String);
method public void closeProfileProxy(int, android.bluetooth.BluetoothProfile);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disable();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enable();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getAddress();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, "android.permission.LOCAL_MAC_ADDRESS"}) public String getAddress();
method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static android.bluetooth.BluetoothAdapter getDefaultAdapter();
method public int getLeMaximumAdvertisingDataLength();
- method public String getName();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getProfileConnectionState(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getProfileConnectionState(int);
method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
method public android.bluetooth.BluetoothDevice getRemoteDevice(String);
method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getScanMode();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getState();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isDiscovering();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEnabled();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getScanMode();
+ method public int getState();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean isDiscovering();
+ method public boolean isEnabled();
method public boolean isLe2MPhySupported();
method public boolean isLeCodedPhySupported();
method public boolean isLeExtendedAdvertisingSupported();
@@ -8640,22 +8642,22 @@
method public boolean isMultipleAdvertisementSupported();
method public boolean isOffloadedFilteringSupported();
method public boolean isOffloadedScanBatchingSupported();
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery();
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
- field public static final String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
- field public static final String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
- field public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
- field public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
- field public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setName(String);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startDiscovery();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
field public static final String ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
field public static final int ERROR = -2147483648; // 0x80000000
field public static final String EXTRA_CONNECTION_STATE = "android.bluetooth.adapter.extra.CONNECTION_STATE";
@@ -9005,38 +9007,38 @@
}
public final class BluetoothDevice implements android.os.Parcelable {
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond();
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBond();
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public int describeContents();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean fetchUuidsWithSdp();
method public String getAddress();
- method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getAlias();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothClass getBluetoothClass();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getBondState();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getName();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getType();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.os.ParcelUuid[] getUuids();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getAlias();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothClass getBluetoothClass();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getBondState();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getType();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelUuid[] getUuids();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setAlias(@NonNull String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPairingConfirmation(boolean);
- method public boolean setPin(byte[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setPin(byte[]);
method public void writeToParcel(android.os.Parcel, int);
- field public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
- field public static final String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
- field public static final String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
- field public static final String ACTION_ALIAS_CHANGED = "android.bluetooth.device.action.ALIAS_CHANGED";
- field public static final String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
- field public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
- field public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
- field public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
- field public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
- field public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ALIAS_CHANGED = "android.bluetooth.device.action.ALIAS_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
field public static final int BOND_BONDED = 12; // 0xc
@@ -9074,30 +9076,30 @@
}
public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
- method public void abortReliableWrite();
- method @Deprecated public void abortReliableWrite(android.bluetooth.BluetoothDevice);
- method public boolean beginReliableWrite();
- method public void close();
- method public boolean connect();
- method public void disconnect();
- method public boolean discoverServices();
- method public boolean executeReliableWrite();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean beginReliableWrite();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void close();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void disconnect();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean discoverServices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean executeReliableWrite();
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public android.bluetooth.BluetoothDevice getDevice();
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
- method public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
- method public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
- method public void readPhy();
- method public boolean readRemoteRssi();
- method public boolean requestConnectionPriority(int);
- method public boolean requestMtu(int);
- method public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
- method public void setPreferredPhy(int, int, int);
- method public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
- method public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readRemoteRssi();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestConnectionPriority(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0
field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1
field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2
@@ -9207,21 +9209,21 @@
}
public final class BluetoothGattServer implements android.bluetooth.BluetoothProfile {
- method public boolean addService(android.bluetooth.BluetoothGattService);
- method public void cancelConnection(android.bluetooth.BluetoothDevice);
- method public void clearServices();
- method public void close();
- method public boolean connect(android.bluetooth.BluetoothDevice, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean addService(android.bluetooth.BluetoothGattService);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void cancelConnection(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void clearServices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void close();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(android.bluetooth.BluetoothDevice, boolean);
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
- method public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
- method public void readPhy(android.bluetooth.BluetoothDevice);
- method public boolean removeService(android.bluetooth.BluetoothGattService);
- method public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
- method public void setPreferredPhy(android.bluetooth.BluetoothDevice, int, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeService(android.bluetooth.BluetoothGattService);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(android.bluetooth.BluetoothDevice, int, int, int);
}
public abstract class BluetoothGattServerCallback {
@@ -9259,18 +9261,18 @@
}
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
- method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isNoiseReductionSupported(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isVoiceRecognitionSupported(@NonNull android.bluetooth.BluetoothDevice);
- method public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, String, String);
- method public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
- method public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
- field public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isNoiseReductionSupported(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isVoiceRecognitionSupported(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, String, String);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
field public static final int AT_CMD_TYPE_ACTION = 4; // 0x4
field public static final int AT_CMD_TYPE_BASIC = 3; // 0x3
field public static final int AT_CMD_TYPE_READ = 0; // 0x0
@@ -9287,14 +9289,14 @@
}
@Deprecated public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
- method @Deprecated public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
- method @Deprecated public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
- method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @Deprecated public int getConnectionState(android.bluetooth.BluetoothDevice);
- method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method @Deprecated public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
- method @Deprecated public boolean registerSinkAppConfiguration(String, int, android.bluetooth.BluetoothHealthCallback);
- method @Deprecated public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean registerSinkAppConfiguration(String, int, android.bluetooth.BluetoothHealthCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
field @Deprecated public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
field @Deprecated public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
field @Deprecated public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
@@ -9325,24 +9327,24 @@
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
- method public boolean connect(android.bluetooth.BluetoothDevice);
- method public boolean disconnect(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback);
- method public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
- method public boolean reportError(android.bluetooth.BluetoothDevice, byte);
- method public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
- method public boolean unregisterApp();
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean reportError(android.bluetooth.BluetoothDevice, byte);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean unregisterApp();
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
field public static final byte ERROR_RSP_INVALID_PARAM = 4; // 0x4
field public static final byte ERROR_RSP_INVALID_RPT_ID = 2; // 0x2
field public static final byte ERROR_RSP_NOT_READY = 1; // 0x1
@@ -9408,26 +9410,26 @@
}
public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
- field public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
+ method public void close();
+ method protected void finalize();
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
}
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(android.bluetooth.BluetoothDevice, int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
- method public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
}
public interface BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
field public static final int A2DP = 2; // 0x2
field public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
field public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
@@ -9458,7 +9460,7 @@
public final class BluetoothSocket implements java.io.Closeable {
method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void connect() throws java.io.IOException;
method public int getConnectionType();
method public java.io.InputStream getInputStream() throws java.io.IOException;
method public int getMaxReceivePacketSize();
@@ -9536,13 +9538,13 @@
}
public final class AdvertisingSet {
- method public void enableAdvertising(boolean, int, int);
- method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
- method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
- method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
- method public void setPeriodicAdvertisingEnabled(boolean);
- method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
- method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void enableAdvertising(boolean, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setScanResponseData(android.bluetooth.le.AdvertiseData);
}
public abstract class AdvertisingSetCallback {
@@ -9605,23 +9607,23 @@
}
public final class BluetoothLeAdvertiser {
- method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
- method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
- method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
- method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
}
public final class BluetoothLeScanner {
- method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void startScan(android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int startScan(@Nullable java.util.List<android.bluetooth.le.ScanFilter>, @Nullable android.bluetooth.le.ScanSettings, @NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopScan(android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopScan(android.app.PendingIntent);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startScan(android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int startScan(@Nullable java.util.List<android.bluetooth.le.ScanFilter>, @Nullable android.bluetooth.le.ScanSettings, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopScan(android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopScan(android.app.PendingIntent);
field public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
field public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
field public static final String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
@@ -11089,7 +11091,6 @@
field public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
field public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
- field public static final String ACTION_PACKAGE_FULLY_LOADED = "android.intent.action.PACKAGE_FULLY_LOADED";
field public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field @Deprecated public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
field public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
@@ -18823,6 +18824,7 @@
package android.hardware.display {
public final class DeviceProductInfo implements android.os.Parcelable {
+ ctor public DeviceProductInfo(@Nullable String, @NonNull String, @NonNull String, @IntRange(from=1990) int, int);
method public int describeContents();
method public int getConnectionToSinkType();
method @IntRange(from=0xffffffff, to=53) public int getManufactureWeek();
@@ -20378,7 +20380,7 @@
method @NonNull public java.util.List<android.media.AudioDeviceInfo> getAvailableCommunicationDevices();
method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice();
method public android.media.AudioDeviceInfo[] getDevices(int);
- method @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public int getEncodedSurroundMode();
+ method public int getEncodedSurroundMode();
method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
method public int getMode();
method public String getParameters(String);
@@ -20401,7 +20403,7 @@
method public static boolean isOffloadedPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
method public boolean isSpeakerphoneOn();
method public boolean isStreamMute(int);
- method @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public boolean isSurroundFormatEnabled(int);
+ method public boolean isSurroundFormatEnabled(int);
method public boolean isVolumeFixed();
method @Deprecated public boolean isWiredHeadsetOn();
method public void loadSoundEffects();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b1e448b..b653410 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -236,7 +236,7 @@
}
public class VpnManager {
- field @Deprecated public static final int TYPE_VPN_LEGACY = 3; // 0x3
+ field public static final int TYPE_VPN_LEGACY = 3; // 0x3
field public static final int TYPE_VPN_NONE = -1; // 0xffffffff
field public static final int TYPE_VPN_OEM = 4; // 0x4
field public static final int TYPE_VPN_PLATFORM = 2; // 0x2
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e290ce4..f7b4cdc 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -371,6 +371,7 @@
field public static final int config_systemAudioIntelligence;
field public static final int config_systemAutomotiveCluster;
field public static final int config_systemAutomotiveProjection;
+ field public static final int config_systemCompanionDeviceProvider;
field public static final int config_systemContacts;
field public static final int config_systemGallery = 17039399; // 0x1040027
field public static final int config_systemNotificationIntelligence;
@@ -961,6 +962,9 @@
field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+ field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
+ field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
+ field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4
field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
@@ -975,10 +979,6 @@
field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
field public static final int STATE_USER_UNMANAGED = 0; // 0x0
- field public static final int SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
- field public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3; // 0x3
- field public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
- field public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
}
public final class SystemUpdatePolicy implements android.os.Parcelable {
@@ -1901,7 +1901,7 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferLengthMillis(int, int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
@@ -1917,22 +1917,22 @@
method public void finalize();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isAudioPlaying(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothAdapter {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method public boolean disableBLE();
- method public boolean enableBLE();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disableBLE();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableBLE();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableNoAutoConnect();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis();
method public boolean isBleScanAlwaysAvailable();
method public boolean isLeEnabled();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeActiveDevice(int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean removeActiveDevice(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
@@ -1948,18 +1948,20 @@
}
public static interface BluetoothAdapter.OobDataCallback {
+ method public void onError(int);
+ method public void onOobData(int, @Nullable android.bluetooth.OobData);
}
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean canBondWithoutDialog();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean cancelBondProcess();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getSimAccessPermission();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isConnected();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeBond();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
@@ -2000,51 +2002,51 @@
}
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getHiSyncId(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothMap implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method public void close();
+ method protected void finalize();
+ method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothMapClient implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.SEND_SMS) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.SEND_SMS}) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent);
}
public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isTetheringOn();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setBluetoothTethering(boolean);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isTetheringOn();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.TETHER_PRIVILEGED}) public void setBluetoothTethering(boolean);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
field public static final int LOCAL_NAP_ROLE = 1; // 0x1
@@ -2058,7 +2060,7 @@
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
}
@@ -2183,9 +2185,9 @@
package android.bluetooth.le {
public final class BluetoothLeScanner {
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
- method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
}
public final class ResultStorageDescriptor implements android.os.Parcelable {
@@ -2934,7 +2936,7 @@
public final class DomainVerificationManager {
method @Nullable @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public android.content.pm.verify.domain.DomainVerificationInfo getDomainVerificationInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
- method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public java.util.List<android.content.pm.verify.domain.DomainOwner> getOwnersForDomain(@NonNull String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public java.util.SortedSet<android.content.pm.verify.domain.DomainOwner> getOwnersForDomain(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> queryValidVerificationPackageNames();
method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationLinkHandlingAllowed(@NonNull String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
method @CheckResult @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public int setDomainVerificationStatus(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7942,16 +7944,16 @@
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnStateCallback(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
}
- public static interface NfcAdapter.ControllerAlwaysOnStateCallback {
- method public void onStateChanged(boolean);
+ public static interface NfcAdapter.ControllerAlwaysOnListener {
+ method public void onControllerAlwaysOnChanged(boolean);
}
public static interface NfcAdapter.NfcUnlockHandler {
@@ -8966,7 +8968,7 @@
package android.provider {
public class CallLog {
- method @RequiresPermission(allOf={android.Manifest.permission.WRITE_CALL_LOG, android.Manifest.permission.INTERACT_ACROSS_USERS}) public static void storeCallComposerPictureAsUser(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull java.io.InputStream, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.net.Uri,android.provider.CallLog.CallComposerLoggingException>);
+ method @RequiresPermission(allOf={android.Manifest.permission.WRITE_CALL_LOG, android.Manifest.permission.INTERACT_ACROSS_USERS}) public static void storeCallComposerPicture(@NonNull android.content.Context, @NonNull java.io.InputStream, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.net.Uri,android.provider.CallLog.CallComposerLoggingException>);
}
public static class CallLog.CallComposerLoggingException extends java.lang.Throwable {
@@ -13626,7 +13628,6 @@
method public int describeContents();
method @Nullable public String getCallIdParameter();
method @NonNull public byte[] getContent();
- method @Deprecated @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
method @NonNull public String getViaBranchParameter();
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index b50b8dd..bf9f4f1 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -51,7 +51,7 @@
package android.bluetooth {
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d59e4f8..a77bf32 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -161,6 +161,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void moveTaskToRootTask(int, int, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksInWindowingModes(@NonNull int[]);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksWithActivityTypes(@NonNull int[]);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean removeTask(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizeTask(int, android.graphics.Rect);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void startSystemLockTaskMode(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void stopSystemLockTaskMode();
@@ -263,10 +264,12 @@
public class BroadcastOptions {
ctor public BroadcastOptions(@NonNull android.os.Bundle);
+ method public int getMaxManifestReceiverApiLevel();
method public long getTemporaryAppAllowlistDuration();
method @Nullable public String getTemporaryAppAllowlistReason();
method public int getTemporaryAppAllowlistReasonCode();
method public int getTemporaryAppAllowlistType();
+ method public void setMaxManifestReceiverApiLevel(int);
}
public class DownloadManager {
@@ -3170,5 +3173,12 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction);
}
+ @UiContext public abstract class WindowProviderService extends android.app.Service {
+ ctor public WindowProviderService();
+ method public final void attachToWindowToken(@NonNull android.os.IBinder);
+ method @Nullable public android.os.Bundle getWindowContextOptions();
+ method public abstract int getWindowType();
+ }
+
}
diff --git a/core/java/android/annotation/RequiresPermission.java b/core/java/android/annotation/RequiresPermission.java
index 1d89e31..303ab41 100644
--- a/core/java/android/annotation/RequiresPermission.java
+++ b/core/java/android/annotation/RequiresPermission.java
@@ -20,7 +20,7 @@
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -76,7 +76,7 @@
*
* @hide
*/
-@Retention(SOURCE)
+@Retention(CLASS)
@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
public @interface RequiresPermission {
/**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index db42803..a24555f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4272,7 +4272,8 @@
try {
getService().broadcastIntentWithFeature(
null, null, intent, null, null, Activity.RESULT_OK, null, null,
- null /*permission*/, appOp, null, false, true, userId);
+ null /*requiredPermissions*/, null /*excludedPermissions*/, appOp, null, false,
+ true, userId);
} catch (RemoteException ex) {
}
}
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 627017c..28d6fbb 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -469,7 +469,8 @@
}
}
- /** @hide */
+ /** Removes task by a given taskId */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
public boolean removeTask(int taskId) {
try {
return getService().removeTask(taskId);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8ff14b0..98fee9c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4390,11 +4390,12 @@
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
- ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
+ final ContextImpl context = ContextImpl.getImpl(service
+ .createServiceBaseContext(this, packageInfo));
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index dfc105a..8574678 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -614,7 +614,7 @@
* tombstone traces will be returned for
* {@link #REASON_CRASH_NATIVE}, with an InputStream containing a protobuf with
* <a href="https://android.googlesource.com/platform/system/core/+/refs/heads/master/debuggerd/proto/tombstone.proto">this schema</a>.
- * Note thatbecause these traces are kept in a separate global circular buffer, crashes may be
+ * Note that because these traces are kept in a separate global circular buffer, crashes may be
* overwritten by newer crashes (including from other applications), so this may still return
* null.
*
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 9da2581..bd7162c 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -250,6 +250,7 @@
* them. This only applies to receivers declared in the app's AndroidManifest.xml.
* @hide
*/
+ @TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void setMaxManifestReceiverApiLevel(int apiLevel) {
mMaxManifestReceiverApiLevel = apiLevel;
@@ -259,6 +260,7 @@
* Return {@link #setMaxManifestReceiverApiLevel}.
* @hide
*/
+ @TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public int getMaxManifestReceiverApiLevel() {
return mMaxManifestReceiverApiLevel;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f7ea381..9753b67 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1176,8 +1176,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- false, getUserId());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1194,7 +1194,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1209,7 +1210,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, false, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1224,7 +1226,24 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, false, false,
+ user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
+ String[] excludedPermissions) {
+ warnIfCallingFromSystemProcess();
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ intent.prepareToLeaveProcess(this);
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions, excludedPermissions,
+ AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1241,7 +1260,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, options, false, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1257,8 +1277,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
- false, getUserId());
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1275,7 +1295,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, null, true, false, getUserId());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, false,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1337,8 +1358,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
- options, true, false, getUserId());
+ rd, initialCode, initialData, initialExtras, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, options, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1351,8 +1372,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- false, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1375,7 +1396,8 @@
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, receiverPermissions,
- AppOpsManager.OP_NONE, options, false, false, user.getIdentifier());
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, options, false, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1391,8 +1413,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
- false, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1442,8 +1464,9 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
- options, true, false, user.getIdentifier());
+ rd, initialCode, initialData, initialExtras, receiverPermissions,
+ null /*excludedPermissions=*/, appOp, options, true, false,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1483,8 +1506,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- true, getUserId());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1522,8 +1545,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
- false, true, getUserId());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, options, false, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1558,8 +1581,9 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
- true, true, getUserId());
+ rd, initialCode, initialData, initialExtras, null,
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1590,8 +1614,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
- true, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, null, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1605,8 +1629,8 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
- false, true, user.getIdentifier());
+ null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
+ AppOpsManager.OP_NONE, options, false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1640,8 +1664,9 @@
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
- rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
- true, true, user.getIdentifier());
+ rd, initialCode, initialData, initialExtras, null,
+ null /*excludedPermissions=*/, AppOpsManager.OP_NONE, null, true, true,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f9279da..89d90a3 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -137,7 +137,7 @@
int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
int broadcastIntentWithFeature(in IApplicationThread caller, in String callingFeatureId,
in Intent intent, in String resolvedType, in IIntentReceiver resultTo, int resultCode,
- in String resultData, in Bundle map, in String[] requiredPermissions,
+ in String resultData, in Bundle map, in String[] requiredPermissions, in String[] excludePermissions,
int appOp, in Bundle options, boolean serialized, boolean sticky, int userId);
void unbroadcastIntent(in IApplicationThread caller, in Intent intent, int userId);
@UnsupportedAppUsage
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a60f1ca..7ce0c70 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1388,6 +1388,12 @@
public static final String EXTRA_CALL_TYPE = "android.callType";
/**
+ * {@link #extras} key: whether the {@link android.app.Notification.CallStyle} notification
+ * is for a call that will activate video when answered. This extra is a boolean.
+ */
+ public static final String EXTRA_CALL_IS_VIDEO = "android.callIsVideo";
+
+ /**
* {@link #extras} key: the person to be displayed as calling for the
* {@link android.app.Notification.CallStyle} notification. This extra is a {@link Person}.
*/
@@ -5110,6 +5116,7 @@
TemplateBindResult result) {
p.headerless(resId == getBaseLayoutResource()
|| resId == getHeadsUpBaseLayoutResource()
+ || resId == getMessagingLayoutResource()
|| resId == R.layout.notification_template_material_media);
RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
@@ -6308,7 +6315,7 @@
* Gets the theme's background color
*/
private @ColorInt int getDefaultBackgroundColor() {
- return obtainThemeColor(R.attr.colorBackground,
+ return obtainThemeColor(R.attr.colorSurface,
mInNightMode ? Color.BLACK : Color.WHITE);
}
@@ -6635,6 +6642,10 @@
return R.layout.notification_template_material_messaging;
}
+ private int getBigMessagingLayoutResource() {
+ return R.layout.notification_template_material_big_messaging;
+ }
+
private int getConversationLayoutResource() {
return R.layout.notification_template_material_conversation;
}
@@ -8145,12 +8156,14 @@
*/
@Override
public RemoteViews makeContentView(boolean increasedHeight) {
+ // All messaging templates contain the actions
ArrayList<Action> originalActions = mBuilder.mActions;
- mBuilder.mActions = new ArrayList<>();
- RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
- false /* hideLargeIcon */);
- mBuilder.mActions = originalActions;
- return remoteViews;
+ try {
+ mBuilder.mActions = new ArrayList<>();
+ return makeMessagingView(StandardTemplateParams.VIEW_TYPE_NORMAL);
+ } finally {
+ mBuilder.mActions = originalActions;
+ }
}
/**
@@ -8236,18 +8249,24 @@
*/
@Override
public RemoteViews makeBigContentView() {
- return makeMessagingView(false /* isCollapsed */, true /* hideLargeIcon */);
+ return makeMessagingView(StandardTemplateParams.VIEW_TYPE_BIG);
}
/**
* Create a messaging layout.
*
- * @param isCollapsed Should this use the collapsed layout
- * @param hideRightIcons Should the reply affordance be shown at the end of the notification
+ * @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_BIG,
+ * VIEW_TYPE_HEADS_UP
* @return the created remoteView.
*/
@NonNull
- private RemoteViews makeMessagingView(boolean isCollapsed, boolean hideRightIcons) {
+ private RemoteViews makeMessagingView(int viewType) {
+ boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_BIG;
+ boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL;
+ boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
+ boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
+ boolean isHeaderless = !isConversationLayout && isCollapsed;
+
CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
? super.mBigContentTitle
: mConversationTitle;
@@ -8265,23 +8284,26 @@
} else {
isOneToOne = !isGroupConversation();
}
- boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
- boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
+ if (isHeaderless && isOneToOne && TextUtils.isEmpty(conversationTitle)) {
+ conversationTitle = getOtherPersonName();
+ }
+
Icon largeIcon = mBuilder.mN.mLargeIcon;
TemplateBindResult bindResult = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
- .viewType(isCollapsed ? StandardTemplateParams.VIEW_TYPE_NORMAL
- : StandardTemplateParams.VIEW_TYPE_BIG)
+ .viewType(viewType)
.highlightExpander(isConversationLayout)
.hideProgress(true)
- .title(conversationTitle)
+ .title(isHeaderless ? conversationTitle : null)
.text(null)
.hideLargeIcon(hideRightIcons || isOneToOne)
- .headerTextSecondary(conversationTitle);
+ .headerTextSecondary(isHeaderless ? null : conversationTitle);
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
isConversationLayout
? mBuilder.getConversationLayoutResource()
- : mBuilder.getMessagingLayoutResource(),
+ : isCollapsed
+ ? mBuilder.getMessagingLayoutResource()
+ : mBuilder.getBigMessagingLayoutResource(),
p,
bindResult);
if (isConversationLayout) {
@@ -8290,14 +8312,6 @@
}
addExtras(mBuilder.mN.extras);
- if (!isConversationLayout) {
- // also update the end margin if there is an image
- // NOTE: This template doesn't support moving this icon to the left, so we don't
- // need to fully apply the MarginSet
- contentView.setViewLayoutMargin(R.id.notification_messaging, RemoteViews.MARGIN_END,
- bindResult.mHeadingExtraMarginSet.getDpValue(),
- TypedValue.COMPLEX_UNIT_DIP);
- }
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
mBuilder.getSmallIconColor(p));
contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
@@ -8323,6 +8337,10 @@
contentView.setBoolean(R.id.status_bar_latest_event_content,
"setIsImportantConversation", isImportantConversation);
}
+ if (isHeaderless) {
+ // Collapsed legacy messaging style has a 1-line limit.
+ contentView.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
+ }
contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
largeIcon);
contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
@@ -8330,6 +8348,22 @@
return contentView;
}
+ private CharSequence getKey(Person person) {
+ return person == null ? null
+ : person.getKey() == null ? person.getName() : person.getKey();
+ }
+
+ private CharSequence getOtherPersonName() {
+ CharSequence userKey = getKey(mUser);
+ for (int i = mMessages.size() - 1; i >= 0; i--) {
+ Person sender = mMessages.get(i).getSenderPerson();
+ if (sender != null && !TextUtils.equals(userKey, getKey(sender))) {
+ return sender.getName();
+ }
+ }
+ return null;
+ }
+
private boolean hasOnlyWhiteSpaceSenders() {
for (int i = 0; i < mMessages.size(); i++) {
Message m = mMessages.get(i);
@@ -8364,12 +8398,7 @@
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
- true /* hideLargeIcon */);
- if (mConversationType == CONVERSATION_TYPE_LEGACY) {
- remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
- }
- return remoteViews;
+ return makeMessagingView(StandardTemplateParams.VIEW_TYPE_HEADS_UP);
}
public static final class Message {
@@ -9146,6 +9175,7 @@
private PendingIntent mAnswerIntent;
private PendingIntent mDeclineIntent;
private PendingIntent mHangUpIntent;
+ private boolean mIsVideo;
private Integer mAnswerButtonColor;
private Integer mDeclineButtonColor;
private Icon mVerificationIcon;
@@ -9238,6 +9268,16 @@
}
/**
+ * Sets whether the call is a video call, which may affect the icons or text used on the
+ * required action buttons.
+ */
+ @NonNull
+ public CallStyle setIsVideo(boolean isVideo) {
+ mIsVideo = isVideo;
+ return this;
+ }
+
+ /**
* Optional icon to be displayed with {@link #setVerificationText(CharSequence) text}
* as a verification status of the caller.
*/
@@ -9365,8 +9405,10 @@
@Nullable
private Action makeAnswerAction() {
- return mAnswerIntent == null ? null : makeAction(R.drawable.ic_call_answer,
- R.string.call_notification_answer_action,
+ return mAnswerIntent == null ? null : makeAction(
+ mIsVideo ? R.drawable.ic_call_answer_video : R.drawable.ic_call_answer,
+ mIsVideo ? R.string.call_notification_answer_video_action
+ : R.string.call_notification_answer_action,
mAnswerButtonColor, R.color.call_notification_answer_color,
mAnswerIntent);
}
@@ -9545,6 +9587,7 @@
public void addExtras(Bundle extras) {
super.addExtras(extras);
extras.putInt(EXTRA_CALL_TYPE, mCallType);
+ extras.putBoolean(EXTRA_CALL_IS_VIDEO, mIsVideo);
extras.putParcelable(EXTRA_CALL_PERSON, mPerson);
if (mVerificationIcon != null) {
extras.putParcelable(EXTRA_VERIFICATION_ICON, mVerificationIcon);
@@ -9587,6 +9630,7 @@
protected void restoreFromExtras(Bundle extras) {
super.restoreFromExtras(extras);
mCallType = extras.getInt(EXTRA_CALL_TYPE);
+ mIsVideo = extras.getBoolean(EXTRA_CALL_IS_VIDEO);
mPerson = extras.getParcelable(EXTRA_CALL_PERSON);
mVerificationIcon = extras.getParcelable(EXTRA_VERIFICATION_ICON);
mVerificationText = extras.getCharSequence(EXTRA_VERIFICATION_TEXT);
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 4cf3a80..ca08683 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -53,7 +53,6 @@
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.ArraySet;
-import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.os.IResultReceiver;
@@ -371,19 +370,9 @@
"Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent");
}
- // TODO(b/178092897) Remove the below instrumentation check and enforce
- // the explicit mutability requirement for apps under instrumentation.
- ActivityThread thread = ActivityThread.currentActivityThread();
- Instrumentation mInstrumentation = thread.getInstrumentation();
-
if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED)
&& !flagImmutableSet && !flagMutableSet) {
-
- if (mInstrumentation.isInstrumenting()) {
- Log.e(TAG, msg);
- } else {
throw new IllegalArgumentException(msg);
- }
}
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 2ceea7f..0ab3f2f 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -861,6 +861,19 @@
}
/**
+ * Creates the base {@link Context} of this {@link Service}.
+ * Users may override this API to create customized base context.
+ *
+ * @see android.window.WindowProviderService WindowProviderService class for example
+ * @see ContextWrapper#attachBaseContext(Context)
+ *
+ * @hide
+ */
+ public Context createServiceBaseContext(ActivityThread mainThread, LoadedApk packageInfo) {
+ return ContextImpl.createAppContext(mainThread, packageInfo);
+ }
+
+ /**
* @hide
* Clean up any references to avoid leaks.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7af9482..4dc0442 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -119,6 +119,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -1214,15 +1215,14 @@
public @interface ProvisioningTrigger {}
/**
- * Possible values for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES}.
+ * Flags for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES}.
*
* @hide
*/
- @IntDef(prefix = { "SUPPORTED_MODES_" }, value = {
- SUPPORTED_MODES_ORGANIZATION_OWNED,
- SUPPORTED_MODES_PERSONALLY_OWNED,
- SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED,
- SUPPORTED_MODES_DEVICE_OWNER
+ @IntDef(flag = true, prefix = { "FLAG_SUPPORTED_MODES_" }, value = {
+ FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED,
+ FLAG_SUPPORTED_MODES_PERSONALLY_OWNED,
+ FLAG_SUPPORTED_MODES_DEVICE_OWNER
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProvisioningConfiguration {}
@@ -1307,7 +1307,7 @@
public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4;
/**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
+ * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
* organization-owned.
*
* <p>Using this value indicates the admin app can only be provisioned in either a
@@ -1316,55 +1316,48 @@
* #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra contain {@link
* #PROVISIONING_MODE_MANAGED_PROFILE} and {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}.
*
- * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
+ * <p>Also, if this flag is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
* will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
* #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
*
- * @hide
- */
- @SystemApi
- public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1;
-
- /**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
- * personally-owned.
- *
- * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
- * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
- * contain only {@link #PROVISIONING_MODE_MANAGED_PROFILE}.
- *
- * @hide
- */
- @SystemApi
- public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2;
-
- /**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning could
- * be organization-owned or personally-owned.
- *
- * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
- * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
- * contain {@link
+ * <p>This flag can be combined with {@link #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED}. In
+ * that case, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity will have
+ * the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra contain {@link
* #PROVISIONING_MODE_MANAGED_PROFILE}, {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE} and
* {@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE}.
*
- * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
- * will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
- * #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
- *
* @hide
*/
@SystemApi
- public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3;
+ public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1;
/**
- * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that the only supported
- * provisioning mode is device owner.
+ * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning
+ * is personally-owned.
+ *
+ * <p>Using this flag will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+ * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
+ * contain only {@link #PROVISIONING_MODE_MANAGED_PROFILE}.
+ *
+ * <p>This flag can be combined with {@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}. In
+ * that case, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity will have the
+ * {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra contain {@link
+ * #PROVISIONING_MODE_MANAGED_PROFILE}, {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE} and
+ * {@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE}.
*
* @hide
*/
@SystemApi
- public static final int SUPPORTED_MODES_DEVICE_OWNER = 4;
+ public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 1 << 1;
+
+ /**
+ * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that the only
+ * supported provisioning mode is device owner.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 1 << 2;
/**
* This MIME type is used for starting the device owner provisioning.
@@ -2637,7 +2630,7 @@
* An integer extra indication what provisioning modes should be available for the admin app
* to pick.
*
- * <p>The default value is {@link #SUPPORTED_MODES_ORGANIZATION_OWNED}.
+ * <p>The default value is {@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}.
*
* <p>The value of this extra will determine the contents of the {@link
* #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array that is passed to the admin app as an
@@ -2648,13 +2641,21 @@
* #ACTION_GET_PROVISIONING_MODE} activity via the {@link #EXTRA_PROVISIONING_IMEI} and {@link
* #EXTRA_PROVISIONING_SERIAL_NUMBER} respectively.
*
+ * <p>The allowed flag combinations are:
+ * <ul>
+ * <li>{@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}</li>
+ * <li>{@link #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED}</li>
+ * <li>{@link #FLAG_SUPPORTED_MODES_DEVICE_OWNER}</li>
+ * <li>{@link #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED}
+ * | {@link #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED}</li>
+ * </ul>
+ *
* <p>This extra is only respected when provided alongside the {@link
* #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent action.
*
- * @see #SUPPORTED_MODES_ORGANIZATION_OWNED
- * @see #SUPPORTED_MODES_PERSONALLY_OWNED
- * @see #SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
- * @see #SUPPORTED_MODES_DEVICE_OWNER
+ * @see #FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED
+ * @see #FLAG_SUPPORTED_MODES_PERSONALLY_OWNED
+ * @see #FLAG_SUPPORTED_MODES_DEVICE_OWNER
* @hide
*/
@SystemApi
@@ -6460,12 +6461,14 @@
* to a given KeyChain key.
*
* Key are granted on a per-UID basis, so if several apps share the same UID, granting access to
- * one of them automatically grants it to others. This method returns a set of sets of package
- * names, where each internal set contains all packages sharing the same UID. Grantee packages
- * that don't share UID with other packages are represented by singleton sets.
+ * one of them automatically grants it to others. This method returns a map containing one entry
+ * per grantee UID. Entries have UIDs as keys and sets of corresponding package names as values.
+ * In particular, grantee packages that don't share UID with other packages are represented by
+ * entries having singleton sets as values.
*
* @param alias The alias of the key to grant access to.
- * @return package names of apps that have access to a given key, grouped by UIDs
+ * @return apps that have access to a given key, arranged in a map from UID to sets of
+ * package names.
*
* @throws SecurityException if the caller is not a device owner, a profile owner or
* delegated certificate chooser.
@@ -6473,26 +6476,11 @@
*
* @see #grantKeyPairToApp(ComponentName, String, String)
*/
- public @NonNull Set<Set<String>> getKeyPairGrants(@NonNull String alias) {
+ public @NonNull Map<Integer, Set<String>> getKeyPairGrants(@NonNull String alias) {
throwIfParentInstance("getKeyPairGrants");
try {
- // Set of sets is flattened into a null-separated list.
- final List<String> flattened =
- mService.getKeyPairGrants(mContext.getPackageName(), alias);
- final Set<Set<String>> result = new HashSet<>();
- Set<String> pkgsForOneUid = new HashSet<>();
- for (final String pkg : flattened) {
- if (pkg == null) {
- result.add(pkgsForOneUid);
- pkgsForOneUid = new HashSet<>();
- } else {
- pkgsForOneUid.add(pkg);
- }
- }
- if (!pkgsForOneUid.isEmpty()) {
- result.add(pkgsForOneUid);
- }
- return result;
+ // The result is wrapped into intermediate parcelable representation.
+ return mService.getKeyPairGrants(mContext.getPackageName(), alias).getPackagesByUid();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 05b0be4..8e86f65 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@
import android.app.admin.NetworkEvent;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
+import android.app.admin.ParcelableGranteeMap;
import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
@@ -485,7 +486,7 @@
boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags);
boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
- List<String> getKeyPairGrants(in String callerPackage, in String alias);
+ ParcelableGranteeMap getKeyPairGrants(in String callerPackage, in String alias);
boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant);
boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias);
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/core/java/android/app/admin/ParcelableGranteeMap.aidl
similarity index 61%
copy from core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
copy to core/java/android/app/admin/ParcelableGranteeMap.aidl
index 1e4fdd7..cd15b49 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
+++ b/core/java/android/app/admin/ParcelableGranteeMap.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 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,16 +14,6 @@
* limitations under the License.
*/
-package android.nfc;
+package android.app.admin;
-/**
- * @hide
- */
-oneway interface INfcControllerAlwaysOnStateCallback {
- /**
- * Called whenever the controller always on state changes
- *
- * @param isEnabled true if the state is enabled, false otherwise
- */
- void onControllerAlwaysOnStateChanged(boolean isEnabled);
-}
+parcelable ParcelableGranteeMap;
\ No newline at end of file
diff --git a/core/java/android/app/admin/ParcelableGranteeMap.java b/core/java/android/app/admin/ParcelableGranteeMap.java
new file mode 100644
index 0000000..be348ad
--- /dev/null
+++ b/core/java/android/app/admin/ParcelableGranteeMap.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Class for marshalling keypair grantees for a given KeyChain key via Binder.
+ *
+ * @hide
+ */
+public class ParcelableGranteeMap implements Parcelable {
+
+ private final Map<Integer, Set<String>> mPackagesByUid;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPackagesByUid.size());
+ for (final Map.Entry<Integer, Set<String>> uidEntry : mPackagesByUid.entrySet()) {
+ dest.writeInt(uidEntry.getKey());
+ dest.writeStringArray(uidEntry.getValue().toArray(new String[0]));
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<ParcelableGranteeMap> CREATOR =
+ new Parcelable.Creator<ParcelableGranteeMap>() {
+ @Override
+ public ParcelableGranteeMap createFromParcel(Parcel source) {
+ final Map<Integer, Set<String>> packagesByUid = new ArrayMap<>();
+ final int numUids = source.readInt();
+ for (int i = 0; i < numUids; i++) {
+ final int uid = source.readInt();
+ final String[] pkgs = source.readStringArray();
+ packagesByUid.put(uid, new ArraySet<>(pkgs));
+ }
+ return new ParcelableGranteeMap(packagesByUid);
+ }
+
+ @Override
+ public ParcelableGranteeMap[] newArray(int size) {
+ return new ParcelableGranteeMap[size];
+ }
+ };
+
+ /**
+ * Creates an instance holding a reference (not a copy) to the given map.
+ */
+ public ParcelableGranteeMap(@NonNull Map<Integer, Set<String>> packagesByUid) {
+ mPackagesByUid = packagesByUid;
+ }
+
+ /**
+ * Returns a reference (not a copy) to the stored map.
+ */
+ @NonNull
+ public Map<Integer, Set<String>> getPackagesByUid() {
+ return mPackagesByUid;
+ }
+}
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index e93138b..759597c 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -28,6 +28,7 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PASSWORD_SIZE;
import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE;
@@ -74,11 +75,8 @@
// consider it a complex PIN/password.
public static final int MAX_ALLOWED_SEQUENCE = 3;
- // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN or CREDENTIAL_TYPE_PASSWORD.
- // Note that this class still uses CREDENTIAL_TYPE_PASSWORD to represent both numeric PIN
- // and alphabetic password. This is OK as long as this definition is only used internally,
- // and the value never gets mixed up with credential types from other parts of the framework.
- // TODO: fix this (ideally after we move logic to PasswordPolicy)
+ // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN, CREDENTIAL_TYPE_PIN or
+ // CREDENTIAL_TYPE_PASSWORD.
public @CredentialType int credType;
// Fields below only make sense when credType is PASSWORD.
public int length = 0;
@@ -192,13 +190,15 @@
/**
* Returns the {@code PasswordMetrics} for a given credential.
*
- * If the credential is a pin or a password, equivalent to {@link #computeForPassword(byte[])}.
- * {@code credential} cannot be null when {@code type} is
+ * If the credential is a pin or a password, equivalent to
+ * {@link #computeForPasswordOrPin(byte[], boolean)}. {@code credential} cannot be null
+ * when {@code type} is
* {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}.
*/
public static PasswordMetrics computeForCredential(LockscreenCredential credential) {
if (credential.isPassword() || credential.isPin()) {
- return PasswordMetrics.computeForPassword(credential.getCredential());
+ return PasswordMetrics.computeForPasswordOrPin(credential.getCredential(),
+ credential.isPin());
} else if (credential.isPattern()) {
return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
} else if (credential.isNone()) {
@@ -209,9 +209,9 @@
}
/**
- * Returns the {@code PasswordMetrics} for a given password
+ * Returns the {@code PasswordMetrics} for a given password or pin
*/
- public static PasswordMetrics computeForPassword(@NonNull byte[] password) {
+ public static PasswordMetrics computeForPasswordOrPin(byte[] password, boolean isPin) {
// Analyse the characters used
int letters = 0;
int upperCase = 0;
@@ -245,8 +245,9 @@
}
}
+ final int credType = isPin ? CREDENTIAL_TYPE_PIN : CREDENTIAL_TYPE_PASSWORD;
final int seqLength = maxLengthSequence(password);
- return new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD, length, letters, upperCase, lowerCase,
+ return new PasswordMetrics(credType, length, letters, upperCase, lowerCase,
numeric, symbols, nonLetter, nonNumeric, seqLength);
}
@@ -353,7 +354,7 @@
*/
public void maxWith(PasswordMetrics other) {
credType = Math.max(credType, other.credType);
- if (credType != CREDENTIAL_TYPE_PASSWORD) {
+ if (credType != CREDENTIAL_TYPE_PASSWORD && credType != CREDENTIAL_TYPE_PIN) {
return;
}
length = Math.max(length, other.length);
@@ -408,7 +409,7 @@
@Override
boolean allowsCredType(int credType) {
- return credType == CREDENTIAL_TYPE_PASSWORD;
+ return credType == CREDENTIAL_TYPE_PASSWORD || credType == CREDENTIAL_TYPE_PIN;
}
},
BUCKET_MEDIUM(PASSWORD_COMPLEXITY_MEDIUM) {
@@ -424,7 +425,7 @@
@Override
boolean allowsCredType(int credType) {
- return credType == CREDENTIAL_TYPE_PASSWORD;
+ return credType == CREDENTIAL_TYPE_PASSWORD || credType == CREDENTIAL_TYPE_PIN;
}
},
BUCKET_LOW(PASSWORD_COMPLEXITY_LOW) {
@@ -489,7 +490,7 @@
if (!bucket.allowsCredType(credType)) {
return false;
}
- if (credType != CREDENTIAL_TYPE_PASSWORD) {
+ if (credType != CREDENTIAL_TYPE_PASSWORD && credType != CREDENTIAL_TYPE_PIN) {
return true;
}
return (bucket.canHaveSequence() || seqLength <= MAX_ALLOWED_SEQUENCE)
@@ -529,7 +530,7 @@
new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0));
}
- final PasswordMetrics enteredMetrics = computeForPassword(password);
+ final PasswordMetrics enteredMetrics = computeForPasswordOrPin(password, isPin);
return validatePasswordMetrics(adminMetrics, minComplexity, isPin, enteredMetrics);
}
@@ -555,8 +556,8 @@
|| !bucket.allowsCredType(actualMetrics.credType)) {
return Collections.singletonList(new PasswordValidationError(WEAK_CREDENTIAL_TYPE, 0));
}
- // TODO: this needs to be modified if CREDENTIAL_TYPE_PIN is added.
- if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD) {
+ if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD
+ && actualMetrics.credType != CREDENTIAL_TYPE_PIN) {
return Collections.emptyList(); // Nothing to check for pattern or none.
}
diff --git a/core/java/android/app/admin/PasswordPolicy.java b/core/java/android/app/admin/PasswordPolicy.java
index 13f11ad..0544a36 100644
--- a/core/java/android/app/admin/PasswordPolicy.java
+++ b/core/java/android/app/admin/PasswordPolicy.java
@@ -20,6 +20,7 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -27,6 +28,7 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
/**
* {@hide}
@@ -58,14 +60,20 @@
} else if (quality == PASSWORD_QUALITY_BIOMETRIC_WEAK
|| quality == PASSWORD_QUALITY_SOMETHING) {
return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
- } // quality is NUMERIC or stronger.
+ } else if (quality == PASSWORD_QUALITY_NUMERIC
+ || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+ PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
+ result.length = length;
+ if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+ result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE;
+ }
+ return result;
+ } // quality is ALPHABETIC or stronger.
PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
result.length = length;
- if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
- result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE;
- } else if (quality == PASSWORD_QUALITY_ALPHABETIC) {
+ if (quality == PASSWORD_QUALITY_ALPHABETIC) {
result.nonNumeric = 1;
} else if (quality == PASSWORD_QUALITY_ALPHANUMERIC) {
result.numeric = 1;
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 2a50e0d..eb4c624 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -65,6 +65,7 @@
void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs,
String callingPackage);
void reportUsageStop(in IBinder activity, String token, String callingPackage);
+ void reportUserInteraction(String packageName, int userId);
int getUsageSource();
void forceUsageSourceSettingRead();
long getLastTimeAnyComponentUsed(String packageName);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 542473a..e8175c7 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -982,6 +982,20 @@
}
/**
+ * Reports user interaction with a given package in the given user.
+ *
+ * <p><em>This method is only for use by the system</em>
+ * @hide
+ */
+ public void reportUserInteraction(@NonNull String packageName, int userId) {
+ try {
+ mService.reportUserInteraction(packageName, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Report usage associated with a particular {@code token} has started. Tokens are app defined
* strings used to represent usage of in-app features. Apps with the {@link
* android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time limit observers
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 16413e1..a268e16 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -23,6 +23,9 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -69,10 +72,10 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
@@ -90,10 +93,10 @@
*
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PLAYING_STATE_CHANGED =
"android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
@@ -112,11 +115,11 @@
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage(trackingBug = 171933273)
public static final String ACTION_ACTIVE_DEVICE_CHANGED =
@@ -133,11 +136,11 @@
* connected, otherwise it is not included.</li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage(trackingBug = 181103983)
public static final String ACTION_CODEC_CONFIG_CHANGED =
@@ -307,7 +310,9 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
@@ -347,7 +352,9 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
@@ -368,6 +375,8 @@
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
try {
@@ -387,6 +396,8 @@
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
try {
@@ -406,6 +417,8 @@
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @BtProfileState int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
try {
@@ -441,7 +454,9 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(trackingBug = 171933273)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
@@ -468,7 +483,9 @@
*/
@UnsupportedAppUsage(trackingBug = 171933273)
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getActiveDevice() {
if (VDBG) log("getActiveDevice()");
try {
@@ -495,7 +512,10 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -514,7 +534,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -546,7 +569,9 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
@@ -620,6 +645,8 @@
* @param volume Absolute volume to be set on AVRCP side
* @hide
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setAvrcpAbsoluteVolume(int volume) {
if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
try {
@@ -636,10 +663,11 @@
/**
* Check if A2DP profile is streaming music.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device BluetoothDevice device
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isA2dpPlaying(BluetoothDevice device) {
try {
final IBluetoothA2dp service = getService();
@@ -662,6 +690,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean shouldSendVolumeKeys(BluetoothDevice device) {
if (isEnabled() && isValidDevice(device)) {
ParcelUuid[] uuids = device.getUuids();
@@ -686,7 +715,9 @@
*/
@UnsupportedAppUsage(trackingBug = 181103983)
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
verifyDeviceNotNull(device, "getCodecStatus");
@@ -714,7 +745,9 @@
* @hide
*/
@UnsupportedAppUsage(trackingBug = 181103983)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setCodecConfigPreference(@NonNull BluetoothDevice device,
@NonNull BluetoothCodecConfig codecConfig) {
if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
@@ -744,7 +777,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void enableOptionalCodecs(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
verifyDeviceNotNull(device, "enableOptionalCodecs");
@@ -759,7 +794,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void disableOptionalCodecs(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
verifyDeviceNotNull(device, "disableOptionalCodecs");
@@ -773,6 +810,7 @@
* active A2DP Bluetooth device.
* @param enable if true, enable the optional codecs, other disable them
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
try {
final IBluetoothA2dp service = getService();
@@ -800,7 +838,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@OptionalCodecsSupportStatus
public int isOptionalCodecsSupported(@NonNull BluetoothDevice device) {
verifyDeviceNotNull(device, "isOptionalCodecsSupported");
@@ -826,7 +866,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@OptionalCodecsPreferenceStatus
public int isOptionalCodecsEnabled(@NonNull BluetoothDevice device) {
verifyDeviceNotNull(device, "isOptionalCodecsEnabled");
@@ -853,7 +895,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setOptionalCodecsEnabled(@NonNull BluetoothDevice device,
@OptionalCodecsPreferenceStatus int value) {
verifyDeviceNotNull(device, "setOptionalCodecsEnabled");
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 67f3d7b..d81316e 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -21,6 +21,9 @@
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -160,7 +163,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothA2dpSink service = getService();
@@ -243,8 +248,6 @@
* Get the current audio configuration for the A2DP source device,
* or null if the device has no audio configuration
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Remote bluetooth device.
* @return audio configuration for the device, or null
*
@@ -252,6 +255,7 @@
*
* @hide
*/
+ @RequiresLegacyBluetoothPermission
public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
if (VDBG) log("getAudioConfig(" + device + ")");
final IBluetoothA2dpSink service = getService();
@@ -278,7 +282,10 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -297,7 +304,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 79fd807..972e9e6 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -17,7 +17,6 @@
package android.bluetooth;
-import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -25,11 +24,18 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.PropertyInvalidatedCache;
import android.bluetooth.BluetoothDevice.Transport;
import android.bluetooth.BluetoothProfile.ConnectionPolicy;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.PeriodicAdvertisingManager;
@@ -98,11 +104,6 @@
* Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
* </p>
* <p>This class is thread safe.</p>
- * <p class="note"><strong>Note:</strong>
- * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
- * permission and some also require the
- * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- * </p>
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>
@@ -144,8 +145,8 @@
* <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
* #EXTRA_PREVIOUS_STATE} containing the new and old states
* respectively.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
@@ -278,8 +279,10 @@
* <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
* for global notification whenever the scan mode changes. For example, an
* application can be notified when the device has ended discoverability.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
@@ -305,8 +308,10 @@
* has rejected the request or an error has occurred.
* <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
* for global notification whenever Bluetooth is turned on or off.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
@@ -325,10 +330,12 @@
* has rejected the request or an error has occurred.
* <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
* for global notification whenever Bluetooth is turned on or off.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE";
@@ -355,8 +362,10 @@
* <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
* #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
* respectively.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
@@ -508,15 +517,19 @@
* progress, and existing connections will experience limited bandwidth
* and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
* discovery.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
/**
* Broadcast Action: The local Bluetooth adapter has finished the device
* discovery process.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
@@ -526,8 +539,10 @@
* <p>This name is visible to remote Bluetooth devices.
* <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
* the name.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
/**
@@ -559,9 +574,10 @@
* {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
* can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
@@ -870,7 +886,7 @@
*
* @return true if the local adapter is turned on
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public boolean isEnabled() {
return getState() == BluetoothAdapter.STATE_ON;
}
@@ -921,6 +937,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disableBLE() {
if (!isBleScanAlwaysAvailable()) {
return false;
@@ -966,6 +983,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enableBLE() {
if (!isBleScanAlwaysAvailable()) {
return false;
@@ -986,6 +1004,7 @@
new PropertyInvalidatedCache<Void, Integer>(
8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(Void query) {
try {
return mService.getState();
@@ -1039,7 +1058,7 @@
*
* @return current state of Bluetooth adapter
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
@AdapterState
public int getState() {
int state = getStateInternal();
@@ -1075,7 +1094,7 @@
* @return current state of Bluetooth adapter
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
@AdapterState
@UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine "
+ "whether you can use BLE & BT classic.")
@@ -1122,7 +1141,9 @@
*
* @return true to indicate adapter startup has begun, or false on immediate error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enable() {
if (isEnabled()) {
if (DBG) {
@@ -1159,7 +1180,9 @@
*
* @return true to indicate adapter shutdown has begun, or false on immediate error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disable() {
try {
return mManagerService.disable(ActivityThread.currentPackageName(), true);
@@ -1172,13 +1195,13 @@
/**
* Turn off the local Bluetooth adapter and don't persist the setting.
*
- * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission
- *
* @return true to indicate adapter shutdown has begun, or false on immediate error
* @hide
*/
@UnsupportedAppUsage(trackingBug = 171933273)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disable(boolean persist) {
try {
@@ -1195,7 +1218,12 @@
*
* @return Bluetooth hardware address as string
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.LOCAL_MAC_ADDRESS,
+ })
public String getAddress() {
try {
return mManagerService.getAddress();
@@ -1208,10 +1236,12 @@
/**
* Get the friendly Bluetooth name of the local Bluetooth adapter.
* <p>This name is visible to remote Bluetooth devices.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @return the Bluetooth name, or null on error
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getName() {
try {
return mManagerService.getName();
@@ -1228,7 +1258,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean factoryReset() {
try {
mServiceLock.readLock().lock();
@@ -1253,7 +1283,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @Nullable ParcelUuid[] getUuids() {
if (getState() != STATE_ON) {
return null;
@@ -1285,7 +1317,9 @@
* @param name a valid Bluetooth name
* @return true if the name was set, false otherwise
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setName(String name) {
if (getState() != STATE_ON) {
return false;
@@ -1311,7 +1345,9 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothClass getBluetoothClass() {
if (getState() != STATE_ON) {
return null;
@@ -1340,7 +1376,7 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setBluetoothClass(BluetoothClass bluetoothClass) {
if (getState() != STATE_ON) {
return false;
@@ -1367,7 +1403,9 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@IoCapability
public int getIoCapability() {
if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
@@ -1395,7 +1433,7 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setIoCapability(@IoCapability int capability) {
if (getState() != STATE_ON) return false;
try {
@@ -1418,7 +1456,9 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@IoCapability
public int getLeIoCapability() {
if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
@@ -1446,7 +1486,7 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setLeIoCapability(@IoCapability int capability) {
if (getState() != STATE_ON) return false;
try {
@@ -1475,7 +1515,9 @@
*
* @return scan mode
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@ScanMode
public int getScanMode() {
if (getState() != STATE_ON) {
@@ -1522,7 +1564,9 @@
*/
@UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which "
+ "shows UI that confirms the user wants to go into discoverable mode.")
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public boolean setScanMode(@ScanMode int mode, long durationMillis) {
if (getState() != STATE_ON) {
return false;
@@ -1571,7 +1615,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public boolean setScanMode(@ScanMode int mode) {
if (getState() != STATE_ON) {
return false;
@@ -1591,6 +1637,7 @@
/** @hide */
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public int getDiscoverableTimeout() {
if (getState() != STATE_ON) {
return -1;
@@ -1610,6 +1657,7 @@
/** @hide */
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void setDiscoverableTimeout(int timeout) {
if (getState() != STATE_ON) {
return;
@@ -1635,7 +1683,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public long getDiscoveryEndMillis() {
try {
mServiceLock.readLock().lock();
@@ -1703,7 +1751,10 @@
*
* @return true on success, false on error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public boolean startDiscovery() {
if (getState() != STATE_ON) {
return false;
@@ -1737,7 +1788,9 @@
*
* @return true on success, false on error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public boolean cancelDiscovery() {
if (getState() != STATE_ON) {
return false;
@@ -1773,7 +1826,9 @@
*
* @return true if discovering
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public boolean isDiscovering() {
if (getState() != STATE_ON) {
return false;
@@ -1805,7 +1860,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean removeActiveDevice(@ActiveDeviceUse int profiles) {
if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
&& profiles != ACTIVE_DEVICE_ALL) {
@@ -1845,7 +1904,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean setActiveDevice(@NonNull BluetoothDevice device,
@ActiveDeviceUse int profiles) {
if (device == null) {
@@ -1889,7 +1952,11 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) {
try {
mServiceLock.readLock().lock();
@@ -1917,7 +1984,10 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) {
try {
mServiceLock.readLock().lock();
@@ -1938,6 +2008,7 @@
*
* @return true if Multiple Advertisement feature is supported
*/
+ @RequiresLegacyBluetoothPermission
public boolean isMultipleAdvertisementSupported() {
if (getState() != STATE_ON) {
return false;
@@ -1981,6 +2052,7 @@
new PropertyInvalidatedCache<Void, Boolean>(
8, BLUETOOTH_FILTERING_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Boolean recompute(Void query) {
try {
mServiceLock.readLock().lock();
@@ -2012,6 +2084,7 @@
*
* @return true if chipset supports on-chip filtering
*/
+ @RequiresLegacyBluetoothPermission
public boolean isOffloadedFilteringSupported() {
if (!getLeAccess()) {
return false;
@@ -2024,6 +2097,7 @@
*
* @return true if chipset supports on-chip scan batching
*/
+ @RequiresLegacyBluetoothPermission
public boolean isOffloadedScanBatchingSupported() {
if (!getLeAccess()) {
return false;
@@ -2046,6 +2120,7 @@
*
* @return true if chipset supports LE 2M PHY feature
*/
+ @RequiresLegacyBluetoothPermission
public boolean isLe2MPhySupported() {
if (!getLeAccess()) {
return false;
@@ -2068,6 +2143,7 @@
*
* @return true if chipset supports LE Coded PHY feature
*/
+ @RequiresLegacyBluetoothPermission
public boolean isLeCodedPhySupported() {
if (!getLeAccess()) {
return false;
@@ -2090,6 +2166,7 @@
*
* @return true if chipset supports LE Extended Advertising feature
*/
+ @RequiresLegacyBluetoothPermission
public boolean isLeExtendedAdvertisingSupported() {
if (!getLeAccess()) {
return false;
@@ -2112,6 +2189,7 @@
*
* @return true if chipset supports LE Periodic Advertising feature
*/
+ @RequiresLegacyBluetoothPermission
public boolean isLePeriodicAdvertisingSupported() {
if (!getLeAccess()) {
return false;
@@ -2135,6 +2213,7 @@
*
* @return the maximum LE advertising data length.
*/
+ @RequiresLegacyBluetoothPermission
public int getLeMaximumAdvertisingDataLength() {
if (!getLeAccess()) {
return 0;
@@ -2172,7 +2251,9 @@
* @return the maximum number of connected audio devices
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getMaxConnectedAudioDevices() {
try {
mServiceLock.readLock().lock();
@@ -2193,6 +2274,7 @@
* @return true if there are hw entries available for matching beacons
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isHardwareTrackingFiltersAvailable() {
if (!getLeAccess()) {
return false;
@@ -2223,6 +2305,7 @@
* instead.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
SynchronousResultReceiver receiver = new SynchronousResultReceiver();
requestControllerActivityEnergyInfo(receiver);
@@ -2248,6 +2331,7 @@
* @param result The callback to which to send the activity info.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void requestControllerActivityEnergyInfo(ResultReceiver result) {
try {
mServiceLock.readLock().lock();
@@ -2275,7 +2359,9 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
if (getState() != STATE_ON) {
return new ArrayList<>();
@@ -2303,7 +2389,9 @@
*
* @return unmodifiable set of {@link BluetoothDevice}, or null on error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public Set<BluetoothDevice> getBondedDevices() {
if (getState() != STATE_ON) {
return toDeviceSet(new BluetoothDevice[0]);
@@ -2368,6 +2456,7 @@
* This method must not be called when mService is null.
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(Void query) {
try {
return mService.getAdapterConnectionState();
@@ -2401,6 +2490,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresLegacyBluetoothPermission
public int getConnectionState() {
if (getState() != STATE_ON) {
return BluetoothAdapter.STATE_DISCONNECTED;
@@ -2429,6 +2519,7 @@
new PropertyInvalidatedCache<Integer, Integer>(
8, BLUETOOTH_PROFILE_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(Integer query) {
try {
mServiceLock.readLock().lock();
@@ -2471,7 +2562,10 @@
* {@link BluetoothProfile#STATE_CONNECTED},
* {@link BluetoothProfile#STATE_DISCONNECTING}
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public int getProfileConnectionState(int profile) {
if (getState() != STATE_ON) {
return BluetoothProfile.STATE_DISCONNECTED;
@@ -2486,7 +2580,6 @@
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
* connections from a listening {@link BluetoothServerSocket}.
* <p>Valid RFCOMM channels are in range 1 to 30.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param channel RFCOMM channel to listen on
* @return a listening RFCOMM BluetoothServerSocket
@@ -2494,6 +2587,9 @@
* permissions, or channel in use.
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
return listenUsingRfcommOn(channel, false, false);
}
@@ -2505,7 +2601,6 @@
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
* connections from a listening {@link BluetoothServerSocket}.
* <p>Valid RFCOMM channels are in range 1 to 30.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
* <p>To auto assign a channel without creating a SDP record use
* {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
*
@@ -2519,6 +2614,9 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm,
boolean min16DigitPin) throws IOException {
BluetoothServerSocket socket =
@@ -2559,7 +2657,9 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions, or channel in use.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
throws IOException {
return createNewRfcommSocketAndRecord(name, uuid, true, true);
@@ -2591,7 +2691,9 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions, or channel in use.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
throws IOException {
return createNewRfcommSocketAndRecord(name, uuid, false, false);
@@ -2622,7 +2724,6 @@
* closed, or if this application closes unexpectedly.
* <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
* connect to this socket from another device using the same {@link UUID}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param name service name for SDP record
* @param uuid uuid for SDP record
@@ -2632,12 +2733,15 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)
throws IOException {
return createNewRfcommSocketAndRecord(name, uuid, false, true);
}
-
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
boolean auth, boolean encrypt) throws IOException {
BluetoothServerSocket socket;
@@ -2663,6 +2767,7 @@
* permissions.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
BluetoothServerSocket socket =
new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port);
@@ -2694,6 +2799,7 @@
* permissions.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
throws IOException {
BluetoothServerSocket socket =
@@ -2726,11 +2832,11 @@
* permissions.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
return listenUsingL2capOn(port, false, false);
}
-
/**
* Construct an insecure L2CAP server socket.
* Call #accept to retrieve connections to this socket.
@@ -2743,6 +2849,7 @@
* permissions.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port);
BluetoothServerSocket socket =
@@ -2769,11 +2876,14 @@
/**
* Read the local Out of Band Pairing Data
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @return Pair<byte[], byte[]> of Hash and Randomizer
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public Pair<byte[], byte[]> readOutOfBandData() {
return null;
}
@@ -2863,6 +2973,7 @@
* @param profile
* @param proxy Profile proxy object
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void closeProfileProxy(int profile, BluetoothProfile proxy) {
if (proxy == null) {
return;
@@ -2937,6 +3048,7 @@
private final IBluetoothManagerCallback mManagerCallback =
new IBluetoothManagerCallback.Stub() {
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
if (DBG) {
Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
@@ -3031,7 +3143,9 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enableNoAutoConnect() {
if (isEnabled()) {
if (DBG) {
@@ -3095,8 +3209,6 @@
*
* @param transport - whether the {@link OobData} is generated for LE or Classic.
* @param oobData - data generated in the host stack(LE) or controller (Classic)
- *
- * @hide
*/
void onOobData(@Transport int transport, @Nullable OobData oobData);
@@ -3104,8 +3216,6 @@
* Provides feedback when things don't go as expected.
*
* @param errorCode - the code descibing the type of error that occurred.
- *
- * @hide
*/
void onError(@OobError int errorCode);
}
@@ -3188,7 +3298,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void generateLocalOobData(@Transport int transport,
@NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) {
if (transport != BluetoothDevice.TRANSPORT_BREDR && transport
@@ -3232,12 +3342,14 @@
* reason. If Bluetooth is already on and if this function is called to turn
* it on, the api will return true and a callback will be called.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
- *
* @param on True for on, false for off.
* @param callback The callback to notify changes to the state.
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean changeApplicationBluetoothState(boolean on,
BluetoothStateChangeCallback callback) {
return false;
@@ -3256,6 +3368,7 @@
/**
* @hide
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
private BluetoothStateChangeCallback mCallback;
@@ -3447,7 +3560,10 @@
* instead.
*/
@Deprecated
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public boolean startLeScan(LeScanCallback callback) {
return startLeScan(null, callback);
}
@@ -3466,7 +3582,10 @@
* instead.
*/
@Deprecated
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
if (DBG) {
Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
@@ -3563,7 +3682,9 @@
* @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead.
*/
@Deprecated
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopLeScan(LeScanCallback callback) {
if (DBG) {
Log.d(TAG, "stopLeScan()");
@@ -3604,7 +3725,9 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions, or unable to start this CoC
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull BluetoothServerSocket listenUsingL2capChannel()
throws IOException {
BluetoothServerSocket socket =
@@ -3650,7 +3773,9 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions, or unable to start this CoC
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel()
throws IOException {
BluetoothServerSocket socket =
@@ -3695,7 +3820,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device,
@NonNull Executor executor, @NonNull OnMetadataChangedListener listener) {
if (DBG) Log.d(TAG, "addOnMetadataChangedListener()");
@@ -3768,7 +3893,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device,
@NonNull OnMetadataChangedListener listener) {
if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()");
@@ -3857,6 +3982,7 @@
* @throws IllegalArgumentException if the callback is already registered
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothConnectionCallback callback) {
if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()");
@@ -3899,6 +4025,7 @@
* @return true if the callback was unregistered successfully, false otherwise
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean unregisterBluetoothConnectionCallback(
@NonNull BluetoothConnectionCallback callback) {
if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()");
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index 4e7e441..887cf3f 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -16,6 +16,10 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -54,10 +58,10 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 0c208fd..1201663 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,6 +25,11 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.PropertyInvalidatedCache;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.companion.AssociationRequest;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -66,9 +70,6 @@
* {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using
* {@link #createL2capChannel(int)} over Bluetooth LE.
*
- * <p class="note"><strong>Note:</strong>
- * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>
@@ -108,10 +109,12 @@
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
* {@link #EXTRA_RSSI} if they are available.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
*/
// TODO: Change API to not broadcast RSSI if not available (incoming connection)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_FOUND =
"android.bluetooth.device.action.FOUND";
@@ -120,9 +123,11 @@
* Broadcast Action: Bluetooth class of a remote device has changed.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
* {@see BluetoothClass}
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CLASS_CHANGED =
"android.bluetooth.device.action.CLASS_CHANGED";
@@ -133,8 +138,10 @@
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
* <p>ACL connections are managed automatically by the Android Bluetooth
* stack.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ACL_CONNECTED =
"android.bluetooth.device.action.ACL_CONNECTED";
@@ -146,8 +153,10 @@
* this intent as a hint to immediately terminate higher level connections
* (RFCOMM, L2CAP, or profile connections) to the remote device.
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ACL_DISCONNECT_REQUESTED =
"android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
@@ -158,8 +167,10 @@
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
* <p>ACL connections are managed automatically by the Android Bluetooth
* stack.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ACL_DISCONNECTED =
"android.bluetooth.device.action.ACL_DISCONNECTED";
@@ -169,8 +180,10 @@
* been retrieved for the first time, or changed since the last retrieval.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_NAME}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_NAME_CHANGED =
"android.bluetooth.device.action.NAME_CHANGED";
@@ -179,9 +192,11 @@
* Broadcast Action: Indicates the alias of a remote device has been
* changed.
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
@SuppressLint("ActionValue")
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ALIAS_CHANGED =
"android.bluetooth.device.action.ALIAS_CHANGED";
@@ -191,10 +206,12 @@
* device. For example, if a device is bonded (paired).
* <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
* #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
// Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
// contain a hidden extra field EXTRA_REASON with the result code.
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BOND_STATE_CHANGED =
"android.bluetooth.device.action.BOND_STATE_CHANGED";
@@ -204,10 +221,12 @@
* been retrieved for the first time, or changed since the last retrieval
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_BATTERY_LEVEL}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BATTERY_LEVEL_CHANGED =
"android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
@@ -642,8 +661,10 @@
* device are requested to be fetched using Service Discovery Protocol
* <p> Always contains the extra field {@link #EXTRA_DEVICE}
* <p> Always contains the extra field {@link #EXTRA_UUID}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to receive.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_UUID =
"android.bluetooth.device.action.UUID";
@@ -657,20 +678,23 @@
* Broadcast Action: Indicates a failure to retrieve the name of a remote
* device.
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*
* @hide
*/
//TODO: is this actually useful?
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_NAME_FAILED =
"android.bluetooth.device.action.NAME_FAILED";
/**
* Broadcast Action: This intent is used to broadcast PAIRING REQUEST
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
- * receive.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PAIRING_REQUEST =
"android.bluetooth.device.action.PAIRING_REQUEST";
@@ -1206,7 +1230,9 @@
*
* @return the Bluetooth name, or null if there was a problem.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getName() {
final IBluetooth service = sService;
if (service == null) {
@@ -1235,7 +1261,9 @@
* @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link
* #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getType() {
final IBluetooth service = sService;
if (service == null) {
@@ -1257,7 +1285,9 @@
* null if there was a problem
*/
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getAlias() {
final IBluetooth service = sService;
if (service == null) {
@@ -1293,7 +1323,9 @@
* @return {@code true} if the alias is successfully set, {@code false} on error
* @throws IllegalArgumentException if the alias is {@code null} or the empty string
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setAlias(@NonNull String alias) {
if (alias == null || alias.isEmpty()) {
throw new IllegalArgumentException("Cannot set the alias to null or the empty string");
@@ -1321,7 +1353,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getBatteryLevel() {
final IBluetooth service = sService;
if (service == null) {
@@ -1346,7 +1380,9 @@
*
* @return false on immediate error, true if bonding will begin
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean createBond() {
return createBond(TRANSPORT_AUTO);
}
@@ -1367,7 +1403,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean createBond(int transport) {
return createBondInternal(transport, null, null);
}
@@ -1395,7 +1433,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data,
@Nullable OobData remoteP256Data) {
if (remoteP192Data == null && remoteP256Data == null) {
@@ -1406,6 +1444,7 @@
return createBondInternal(transport, remoteP192Data, remoteP256Data);
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
@Nullable OobData remoteP256Data) {
final IBluetooth service = sService;
@@ -1430,7 +1469,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isBondingInitiatedLocally() {
final IBluetooth service = sService;
if (service == null) {
@@ -1452,7 +1493,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean cancelBondProcess() {
final IBluetooth service = sService;
if (service == null) {
@@ -1480,7 +1521,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean removeBond() {
final IBluetooth service = sService;
if (service == null) {
@@ -1504,6 +1545,7 @@
new PropertyInvalidatedCache<BluetoothDevice, Integer>(
8, BLUETOOTH_BONDING_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(BluetoothDevice query) {
try {
return sService.getBondState(query);
@@ -1532,7 +1574,10 @@
*
* @return the bond state
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public int getBondState() {
final IBluetooth service = sService;
if (service == null) {
@@ -1560,7 +1605,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean canBondWithoutDialog() {
final IBluetooth service = sService;
if (service == null) {
@@ -1583,7 +1628,9 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected() {
final IBluetooth service = sService;
if (service == null) {
@@ -1606,7 +1653,9 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isEncrypted() {
final IBluetooth service = sService;
if (service == null) {
@@ -1626,7 +1675,9 @@
*
* @return Bluetooth class object, or null on error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothClass getBluetoothClass() {
final IBluetooth service = sService;
if (service == null) {
@@ -1653,7 +1704,9 @@
*
* @return the supported features (UUIDs) of the remote device, or null on error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public ParcelUuid[] getUuids() {
final IBluetooth service = sService;
if (service == null || !isBluetoothEnabled()) {
@@ -1681,7 +1734,9 @@
* @return False if the check fails, True if the process of initiating an ACL connection
* to the remote device was started.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean fetchUuidsWithSdp() {
final IBluetooth service = sService;
if (service == null || !isBluetoothEnabled()) {
@@ -1707,8 +1762,7 @@
* {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
* Detailed status error codes can be found by members of the Bluetooth package in
* the AbstractionLayer class.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
- * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
+ * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
* The object type will match one of the SdpXxxRecord types, depending on the UUID searched
* for.
*
@@ -1717,6 +1771,9 @@
* was started.
*/
/** @hide */
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sdpSearch(ParcelUuid uuid) {
final IBluetooth service = sService;
if (service == null) {
@@ -1733,10 +1790,12 @@
/**
* Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
* @return true pin has been set false for error
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setPin(byte[] pin) {
final IBluetooth service = sService;
if (service == null) {
@@ -1758,7 +1817,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setPin(@NonNull String pin) {
byte[] pinBytes = convertPinToBytes(pin);
if (pinBytes == null) {
@@ -1772,7 +1833,7 @@
*
* @return true confirmation has been sent out false for error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setPairingConfirmation(boolean confirm) {
final IBluetooth service = sService;
if (service == null) {
@@ -1795,7 +1856,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean cancelPairing() {
final IBluetooth service = sService;
if (service == null) {
@@ -1827,7 +1890,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @AccessPermission int getPhonebookAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -1859,8 +1924,6 @@
* If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
* enter silence mode.
*
- * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
- *
* @param silence true to enter silence mode, false to exit
* @return true on success, false on error.
* @throws IllegalStateException if Bluetooth is not turned ON.
@@ -1884,8 +1947,6 @@
/**
* Check whether the {@link BluetoothDevice} is in silence mode
*
- * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
- *
* @return true on device in silence mode, otherwise false.
* @throws IllegalStateException if Bluetooth is not turned ON.
* @hide
@@ -1935,7 +1996,9 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @AccessPermission int getMessageAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -1959,7 +2022,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setMessageAccessPermission(@AccessPermission int value) {
// Validates param value is one of the accepted constants
if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
@@ -1984,7 +2047,9 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @AccessPermission int getSimAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -2008,7 +2073,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setSimAccessPermission(int value) {
final IBluetooth service = sService;
if (service == null) {
@@ -2039,7 +2104,6 @@
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid RFCOMM channels are in range 1 to 30.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param channel RFCOMM channel to connect to
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
@@ -2048,6 +2112,10 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createRfcommSocket(int channel) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2074,7 +2142,6 @@
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid L2CAP PSM channels are in range 1 to 2^16.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param channel L2cap PSM/channel to connect to
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
@@ -2082,6 +2149,10 @@
* permissions
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createL2capSocket(int channel) throws IOException {
return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
null);
@@ -2095,7 +2166,6 @@
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid L2CAP PSM channels are in range 1 to 2^16.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param channel L2cap PSM/channel to connect to
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
@@ -2103,6 +2173,10 @@
* permissions
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
null);
@@ -2138,7 +2212,10 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2176,7 +2253,10 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2192,7 +2272,6 @@
* Call #connect on the returned #BluetoothSocket to begin the connection.
* The remote device will not be authenticated and communication on this
* socket will not be encrypted.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param port remote port
* @return An RFCOMM BluetoothSocket
@@ -2202,6 +2281,10 @@
*/
@UnsupportedAppUsage(publicAlternatives = "Use "
+ "{@link #createInsecureRfcommSocketToServiceRecord} instead.")
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2214,7 +2297,6 @@
/**
* Construct a SCO socket ready to start an outgoing connection.
* Call #connect on the returned #BluetoothSocket to begin the connection.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @return a SCO BluetoothSocket
* @throws IOException on error, for example Bluetooth not available, or insufficient
@@ -2222,6 +2304,10 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createScoSocket() throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2269,6 +2355,8 @@
* automatically connect as soon as the remote device becomes available (true).
* @throws IllegalArgumentException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
@@ -2289,6 +2377,8 @@
* BluetoothDevice#TRANSPORT_LE}
* @throws IllegalArgumentException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport) {
return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
@@ -2313,6 +2403,8 @@
* is set to true.
* @throws NullPointerException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport, int phy) {
return connectGatt(context, autoConnect, callback, transport, phy, null);
@@ -2339,6 +2431,8 @@
* an un-specified background thread.
* @throws NullPointerException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport, int phy,
Handler handler) {
@@ -2372,6 +2466,8 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport,
boolean opportunistic, int phy, Handler handler) {
@@ -2416,7 +2512,10 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
@@ -2444,7 +2543,10 @@
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
@@ -2472,7 +2574,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
final IBluetooth service = sService;
if (service == null) {
@@ -2500,7 +2602,7 @@
*/
@SystemApi
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public byte[] getMetadata(@MetadataKey int key) {
final IBluetooth service = sService;
if (service == null) {
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 381318b..942f843 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -17,6 +17,14 @@
package android.bluetooth;
import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelUuid;
@@ -157,6 +165,7 @@
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onClientRegistered(int status, int clientIf) {
if (DBG) {
Log.d(TAG, "onClientRegistered() - status=" + status
@@ -347,6 +356,7 @@
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onCharacteristicRead(String address, int status, int handle,
byte[] value) {
if (VDBG) {
@@ -404,6 +414,7 @@
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onCharacteristicWrite(String address, int status, int handle) {
if (VDBG) {
Log.d(TAG, "onCharacteristicWrite() - Device=" + address
@@ -487,6 +498,7 @@
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onDescriptorRead(String address, int status, int handle, byte[] value) {
if (VDBG) {
Log.d(TAG,
@@ -538,6 +550,7 @@
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onDescriptorWrite(String address, int status, int handle) {
if (VDBG) {
Log.d(TAG,
@@ -734,6 +747,7 @@
* Application should call this method as early as possible after it is done with
* this GATT client.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void close() {
if (DBG) Log.d(TAG, "close()");
@@ -817,12 +831,13 @@
* <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
* is used to notify success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @return If true, the callback will be called to notify success or failure, false on immediate
* error
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
return registerApp(callback, handler, false);
}
@@ -833,14 +848,15 @@
* <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
* is used to notify success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param eatt_support indicate to allow for eatt support
* @return If true, the callback will be called to notify success or failure, false on immediate
* error
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean registerApp(BluetoothGattCallback callback, Handler handler,
boolean eatt_support) {
if (DBG) Log.d(TAG, "registerApp()");
@@ -865,6 +881,7 @@
* Unregister the current application and callbacks.
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void unregisterApp() {
if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
if (mService == null || mClientIf == 0) return;
@@ -893,14 +910,15 @@
* subsequent connections to known devices should be invoked with the
* autoConnect parameter set to true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Remote device to connect to
* @param autoConnect Whether to directly connect to the remote device (false) or to
* automatically connect as soon as the remote device becomes available (true).
* @return true, if the connection attempt was initiated successfully
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
Handler handler) {
if (DBG) {
@@ -931,9 +949,10 @@
/**
* Disconnects an established connection, or cancels a connection attempt
* currently in progress.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void disconnect() {
if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return;
@@ -954,6 +973,7 @@
*
* @return true, if the connection attempt was initiated successfully
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect() {
try {
mService.clientConnect(mClientIf, mDevice.getAddress(), false, mTransport,
@@ -983,6 +1003,7 @@
* of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
* {@link BluetoothDevice#PHY_OPTION_S8}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
try {
mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy,
@@ -996,6 +1017,7 @@
* Read the current transmitter PHY and receiver PHY of the connection. The values are returned
* in {@link BluetoothGattCallback#onPhyRead}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy() {
try {
mService.clientReadPhy(mClientIf, mDevice.getAddress());
@@ -1022,10 +1044,11 @@
* triggered. If the discovery was successful, the remote services can be
* retrieved using the {@link #getServices} function.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the remote service discovery has been started
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean discoverServices() {
if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1047,11 +1070,12 @@
* It should never be used by real applications. The service is not searched
* for characteristics and descriptors, or returned in any callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the remote service discovery has been started
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean discoverServiceByUuid(UUID uuid) {
if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1073,11 +1097,10 @@
* <p>This function requires that service discovery has been completed
* for the given device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return List of services on the remote device. Returns an empty list if service discovery has
* not yet been performed.
*/
+ @RequiresLegacyBluetoothPermission
public List<BluetoothGattService> getServices() {
List<BluetoothGattService> result =
new ArrayList<BluetoothGattService>();
@@ -1101,12 +1124,11 @@
* <p>If multiple instances of the same service (as identified by UUID)
* exist, the first instance of the service is returned.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param uuid UUID of the requested service
* @return BluetoothGattService if supported, or null if the requested service is not offered by
* the remote device.
*/
+ @RequiresLegacyBluetoothPermission
public BluetoothGattService getService(UUID uuid) {
for (BluetoothGattService service : mServices) {
if (service.getDevice().equals(mDevice) && service.getUuid().equals(uuid)) {
@@ -1124,11 +1146,12 @@
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
* callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param characteristic Characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) == 0) {
return false;
@@ -1167,12 +1190,13 @@
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
* callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param uuid UUID of characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
if (mService == null || mClientIf == 0) return false;
@@ -1202,11 +1226,12 @@
* {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
* reporting the result of the operation.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param characteristic Characteristic to write on the remote device
* @return true, if the write operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
&& (characteristic.getProperties()
@@ -1248,11 +1273,12 @@
* {@link BluetoothGattCallback#onDescriptorRead} callback is
* triggered, signaling the result of the operation.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param descriptor Descriptor value to read from the remote device
* @return true, if the read operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readDescriptor(BluetoothGattDescriptor descriptor) {
if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid());
if (mService == null || mClientIf == 0) return false;
@@ -1289,11 +1315,12 @@
* <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is
* triggered to report the result of the write operation.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param descriptor Descriptor to write to the associated remote device
* @return true, if the write operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false;
@@ -1340,10 +1367,11 @@
* cancel the current transaction without committing any values on the
* remote device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the reliable write transaction has been initiated
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean beginReliableWrite() {
if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1367,10 +1395,11 @@
* <p>A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is
* invoked to indicate whether the transaction has been executed correctly.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the request to execute the transaction has been sent
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean executeReliableWrite() {
if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1396,9 +1425,10 @@
*
* <p>Calling this function will discard all queued characteristic write
* operations for a given remote device.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void abortReliableWrite() {
if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return;
@@ -1414,6 +1444,7 @@
* @deprecated Use {@link #abortReliableWrite()}
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void abortReliableWrite(BluetoothDevice mDevice) {
abortReliableWrite();
}
@@ -1426,12 +1457,13 @@
* triggered if the remote device indicates that the given characteristic
* has changed.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param characteristic The characteristic for which to enable notifications
* @param enable Set to true to enable notifications/indications
* @return true, if the requested notification status was set successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enable) {
if (DBG) {
@@ -1464,6 +1496,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean refresh() {
if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1484,10 +1517,11 @@
* <p>The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be
* invoked when the RSSI value has been read.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the RSSI value has been requested successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readRemoteRssi() {
if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1512,10 +1546,11 @@
* <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
* whether this operation was successful.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the new MTU value has been requested successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestMtu(int mtu) {
if (DBG) {
Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
@@ -1544,6 +1579,7 @@
* or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
* @throws IllegalArgumentException If the parameters are outside of their specified range.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestConnectionPriority(int connectionPriority) {
if (connectionPriority < CONNECTION_PRIORITY_BALANCED
|| connectionPriority > CONNECTION_PRIORITY_LOW_POWER) {
@@ -1571,6 +1607,7 @@
* @return true, if the request is send to the Bluetooth stack.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestLeConnectionUpdate(int minConnectionInterval, int maxConnectionInterval,
int slaveLatency, int supervisionTimeout,
int minConnectionEventLen, int maxConnectionEventLen) {
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 8f1b59c..8a7d4ba 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -237,7 +237,6 @@
/**
* Create a new BluetoothGattCharacteristic.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this characteristic
* @param properties Properties of this characteristic
@@ -344,7 +343,6 @@
/**
* Adds a descriptor to this characteristic.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param descriptor Descriptor to be added to this characteristic.
* @return true, if the descriptor was added to the characteristic
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index 49ba281..ed5ea08 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -128,7 +128,6 @@
/**
* Create a new BluetoothGattDescriptor.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this descriptor
* @param permissions Permissions for this descriptor
@@ -139,7 +138,6 @@
/**
* Create a new BluetoothGattDescriptor.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic The characteristic this descriptor belongs to
* @param uuid The UUID for this descriptor
@@ -228,8 +226,6 @@
* <p>If a remote device offers multiple descriptors with the same UUID,
* the instance ID is used to distuinguish between descriptors.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return Instance ID of this descriptor
* @hide
*/
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 088b016..fdb8018 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -16,6 +16,9 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
@@ -425,6 +428,7 @@
* Application should call this method as early as possible after it is done with
* this GATT server.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void close() {
if (DBG) Log.d(TAG, "close()");
unregisterCallback();
@@ -436,12 +440,13 @@
* <p>This is an asynchronous call. The callback is used to notify
* success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @return true, the callback will be called to notify success or failure, false on immediate
* error
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
return registerCallback(callback, false);
}
@@ -452,14 +457,15 @@
* <p>This is an asynchronous call. The callback is used to notify
* success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param eatt_support indicates if server can use eatt
* @return true, the callback will be called to notify success or failure, false on immediate
* error
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ boolean registerCallback(BluetoothGattServerCallback callback,
boolean eatt_support) {
if (DBG) Log.d(TAG, "registerCallback()");
@@ -504,6 +510,7 @@
/**
* Unregister the current application and callbacks.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void unregisterCallback() {
if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
if (mService == null || mServerIf == 0) return;
@@ -548,12 +555,13 @@
* subsequent connections to known devices should be invoked with the
* autoConnect parameter set to true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param autoConnect Whether to directly connect to the remote device (false) or to
* automatically connect as soon as the remote device becomes available (true).
* @return true, if the connection attempt was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device, boolean autoConnect) {
if (DBG) {
Log.d(TAG,
@@ -576,10 +584,11 @@
* Disconnects an established connection, or cancels a connection attempt
* currently in progress.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Remote device
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void cancelConnection(BluetoothDevice device) {
if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress());
if (mService == null || mServerIf == 0) return;
@@ -609,6 +618,7 @@
* of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
* {@link BluetoothDevice#PHY_OPTION_S8}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setPreferredPhy(BluetoothDevice device, int txPhy, int rxPhy, int phyOptions) {
try {
mService.serverSetPreferredPhy(mServerIf, device.getAddress(), txPhy, rxPhy,
@@ -624,6 +634,7 @@
*
* @param device The remote device to send this response to
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy(BluetoothDevice device) {
try {
mService.serverReadPhy(mServerIf, device.getAddress());
@@ -645,14 +656,15 @@
* <li>{@link BluetoothGattServerCallback#onDescriptorWriteRequest}
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote device to send this response to
* @param requestId The ID of the request that was received with the callback
* @param status The status of the request to be sent to the remote devices
* @param offset Value offset for partial read/write response
* @param value The value of the attribute that was read/written (optional)
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendResponse(BluetoothDevice device, int requestId,
int status, int offset, byte[] value) {
if (VDBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress());
@@ -677,8 +689,6 @@
* for every client that requests notifications/indications by writing
* to the "Client Configuration" descriptor for the given characteristic.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote device to receive the notification/indication
* @param characteristic The local characteristic that has been updated
* @param confirm true to request confirmation from the client (indication), false to send a
@@ -686,6 +696,9 @@
* @return true, if the notification has been triggered successfully
* @throws IllegalArgumentException
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean notifyCharacteristicChanged(BluetoothDevice device,
BluetoothGattCharacteristic characteristic, boolean confirm) {
if (VDBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
@@ -724,11 +737,12 @@
* whether this service has been added successfully. Do not add another service
* before this callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param service Service to be added to the list of services provided by this device.
* @return true, if the request to add service has been initiated
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean addService(BluetoothGattService service) {
if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid());
if (mService == null || mServerIf == 0) return false;
@@ -748,11 +762,12 @@
/**
* Removes a service from the list of services to be provided.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param service Service to be removed.
* @return true, if the service has been removed
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean removeService(BluetoothGattService service) {
if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid());
if (mService == null || mServerIf == 0) return false;
@@ -774,8 +789,10 @@
/**
* Remove all services from the list of provided services.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void clearServices() {
if (DBG) Log.d(TAG, "clearServices()");
if (mService == null || mServerIf == 0) return;
@@ -794,10 +811,9 @@
* <p>An application must call {@link #addService} to add a serice to the
* list of services offered by this device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return List of services. Returns an empty list if no services have been added yet.
*/
+ @RequiresLegacyBluetoothPermission
public List<BluetoothGattService> getServices() {
return mServices;
}
@@ -809,12 +825,11 @@
* <p>If multiple instances of the same service (as identified by UUID)
* exist, the first instance of the service is returned.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param uuid UUID of the requested service
* @return BluetoothGattService if supported, or null if the requested service is not offered by
* this device.
*/
+ @RequiresLegacyBluetoothPermission
public BluetoothGattService getService(UUID uuid) {
for (BluetoothGattService service : mServices) {
if (service.getUuid().equals(uuid)) {
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 23dc7c8..f64d09f 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -15,6 +15,9 @@
*/
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -98,7 +101,6 @@
/**
* Create a new BluetoothGattService.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this service
* @param serviceType The type of this service,
@@ -225,11 +227,11 @@
/**
* Add an included service to this service.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param service The service to be added
* @return true, if the included service was added to the service
*/
+ @RequiresLegacyBluetoothPermission
public boolean addService(BluetoothGattService service) {
mIncludedServices.add(service);
return true;
@@ -237,11 +239,11 @@
/**
* Add a characteristic to this service.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic The characteristics to be added
* @return true, if the characteristic was added to the service
*/
+ @RequiresLegacyBluetoothPermission
public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {
mCharacteristics.add(characteristic);
characteristic.setService(this);
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 632572d..84e8c51 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -22,6 +22,9 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -70,10 +73,10 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
@@ -90,10 +93,10 @@
* </ul>
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_AUDIO_CONNECTED}, {@link #STATE_AUDIO_DISCONNECTED},
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission
- * to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_AUDIO_STATE_CHANGED =
"android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
@@ -107,11 +110,11 @@
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage(trackingBug = 171933273)
public static final String ACTION_ACTIVE_DEVICE_CHANGED =
@@ -147,9 +150,10 @@
* <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = AT_CMD_TYPE_SET </li>
* <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = foo, 3 </li>
* </ul>
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission
- * to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT =
"android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
@@ -299,10 +303,12 @@
* are given an assigned number. Below shows the assigned number of Indicator added so far
* - Enhanced Safety - 1, Valid Values: 0 - Disabled, 1 - Enabled
* - Battery Level - 2, Valid Values: 0~100 - Remaining level of Battery
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
*
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public static final String ACTION_HF_INDICATORS_VALUE_CHANGED =
"android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED";
@@ -432,15 +438,17 @@
* the state. Users can get the connection state of the profile
* from this intent.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -474,15 +482,14 @@
* {@link #STATE_DISCONNECTING} can be used to distinguish between the
* two scenarios.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -502,6 +509,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHeadset service = mService;
@@ -521,6 +529,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHeadset service = mService;
@@ -540,6 +549,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getConnectionState(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -571,7 +581,12 @@
*/
@Deprecated
@SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothHeadset service = mService;
@@ -605,7 +620,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -638,7 +657,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -688,7 +709,9 @@
* @param device Bluetooth device
* @return true if echo cancellation and/or noise reduction is supported, false otherwise
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isNoiseReductionSupported(@NonNull BluetoothDevice device) {
if (DBG) log("isNoiseReductionSupported()");
final IBluetoothHeadset service = mService;
@@ -709,7 +732,9 @@
* @param device Bluetooth device
* @return true if voice recognition is supported, false otherwise
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isVoiceRecognitionSupported(@NonNull BluetoothDevice device) {
if (DBG) log("isVoiceRecognitionSupported()");
final IBluetoothHeadset service = mService;
@@ -738,13 +763,17 @@
* audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
* in case of failure to establish the audio connection.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset
* @return false if there is no headset connected, or the connected headset doesn't support
* voice recognition, or voice recognition is already started, or audio channel is occupied,
* or on error, true otherwise
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean startVoiceRecognition(BluetoothDevice device) {
if (DBG) log("startVoiceRecognition()");
final IBluetoothHeadset service = mService;
@@ -767,12 +796,13 @@
* If this function returns true, this intent will be broadcasted with
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset
* @return false if there is no headset connected, or voice recognition has not started,
* or voice recognition has ended on this headset, or on error, true otherwise
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean stopVoiceRecognition(BluetoothDevice device) {
if (DBG) log("stopVoiceRecognition()");
final IBluetoothHeadset service = mService;
@@ -790,11 +820,12 @@
/**
* Check if Bluetooth SCO audio is connected.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset
* @return true if SCO is connected, false otherwise or on error
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isAudioConnected(BluetoothDevice device) {
if (VDBG) log("isAudioConnected()");
final IBluetoothHeadset service = mService;
@@ -827,6 +858,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getAudioState(BluetoothDevice device) {
if (VDBG) log("getAudioState");
final IBluetoothHeadset service = mService;
@@ -853,6 +885,7 @@
* @param allowed {@code true} if the profile can reroute audio, {@code false} otherwise.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setAudioRouteAllowed(boolean allowed) {
if (VDBG) log("setAudioRouteAllowed");
final IBluetoothHeadset service = mService;
@@ -874,6 +907,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getAudioRouteAllowed() {
if (VDBG) log("getAudioRouteAllowed");
final IBluetoothHeadset service = mService;
@@ -897,6 +931,7 @@
* False to use SCO audio in normal manner
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setForceScoAudio(boolean forced) {
if (VDBG) log("setForceScoAudio " + String.valueOf(forced));
final IBluetoothHeadset service = mService;
@@ -915,12 +950,13 @@
/**
* Check if at least one headset's SCO audio is connected or connecting
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true if at least one device's SCO audio is connected or connecting, false otherwise
* or on error
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isAudioOn() {
if (VDBG) log("isAudioOn()");
final IBluetoothHeadset service = mService;
@@ -955,6 +991,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connectAudio() {
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
@@ -982,6 +1019,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnectAudio() {
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
@@ -1018,7 +1056,12 @@
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
@UnsupportedAppUsage
public boolean startScoUsingVirtualVoiceCall() {
if (DBG) log("startScoUsingVirtualVoiceCall()");
@@ -1048,7 +1091,12 @@
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
@UnsupportedAppUsage
public boolean stopScoUsingVirtualVoiceCall() {
if (DBG) log("stopScoUsingVirtualVoiceCall()");
@@ -1075,6 +1123,10 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public void phoneStateChanged(int numActive, int numHeld, int callState, String number,
int type, String name) {
final IBluetoothHeadset service = mService;
@@ -1095,6 +1147,10 @@
*
* @hide
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public void clccResponse(int index, int direction, int status, int mode, boolean mpty,
String number, int type) {
final IBluetoothHeadset service = mService;
@@ -1119,8 +1175,6 @@
*
* <p>Currently only {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} is allowed as {@code command}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset.
* @param command A vendor-specific command.
* @param arg The argument that will be attached to the command.
@@ -1128,6 +1182,9 @@
* vendor-specific unsolicited result code, or on error. {@code true} otherwise.
* @throws IllegalArgumentException if {@code command} is {@code null}.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendVendorSpecificResultCode(BluetoothDevice device, String command,
String arg) {
if (DBG) {
@@ -1164,15 +1221,17 @@
* {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
* with the active device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device Remote Bluetooth Device, could be null if phone call audio should not be
* streamed to a headset
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
@UnsupportedAppUsage(trackingBug = 171933273)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) {
@@ -1201,7 +1260,9 @@
*/
@UnsupportedAppUsage(trackingBug = 171933273)
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getActiveDevice() {
if (VDBG) {
Log.d(TAG, "getActiveDevice");
@@ -1227,7 +1288,9 @@
* @return true if in-band ringing is enabled, false if in-band ringing is disabled
* @hide
*/
- @RequiresPermission(android.Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isInbandRingingEnabled() {
if (DBG) {
log("isInbandRingingEnabled()");
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index e5b2a1e..092130d 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -19,6 +19,8 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -447,6 +449,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -473,6 +476,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -495,6 +499,7 @@
* @return list of connected devices; empty list if nothing is connected.
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHeadsetClient service =
@@ -519,6 +524,7 @@
* list if nothing matches the <code>states</code>
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHeadsetClient service =
@@ -542,6 +548,7 @@
* @return the state of connection of the device
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getConnectionState(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -569,7 +576,7 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -587,7 +594,7 @@
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -619,7 +626,9 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -636,7 +645,9 @@
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -664,6 +675,7 @@
* #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
* is not supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean startVoiceRecognition(BluetoothDevice device) {
if (DBG) log("startVoiceRecognition()");
final IBluetoothHeadsetClient service =
@@ -688,6 +700,7 @@
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId,
String atCommand) {
if (DBG) log("sendVendorSpecificCommand()");
@@ -715,6 +728,7 @@
* #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
* is not supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean stopVoiceRecognition(BluetoothDevice device) {
if (DBG) log("stopVoiceRecognition()");
final IBluetoothHeadsetClient service =
@@ -736,6 +750,7 @@
* @param device remote device
* @return list of calls; empty list if none call exists
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()");
final IBluetoothHeadsetClient service =
@@ -757,6 +772,7 @@
* @param device remote device
* @return bundle of AG indicators; null if device is not in CONNECTED state
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public Bundle getCurrentAgEvents(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()");
final IBluetoothHeadsetClient service =
@@ -782,6 +798,7 @@
* otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean acceptCall(BluetoothDevice device, int flag) {
if (DBG) log("acceptCall()");
final IBluetoothHeadsetClient service =
@@ -804,6 +821,7 @@
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean holdCall(BluetoothDevice device) {
if (DBG) log("holdCall()");
final IBluetoothHeadsetClient service =
@@ -831,6 +849,7 @@
* supported.</p>
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean rejectCall(BluetoothDevice device) {
if (DBG) log("rejectCall()");
final IBluetoothHeadsetClient service =
@@ -862,6 +881,7 @@
* #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
* supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) {
if (DBG) log("terminateCall()");
final IBluetoothHeadsetClient service =
@@ -891,6 +911,7 @@
* #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
* supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enterPrivateMode(BluetoothDevice device, int index) {
if (DBG) log("enterPrivateMode()");
final IBluetoothHeadsetClient service =
@@ -919,6 +940,7 @@
* #EXTRA_AG_FEATURE_MERGE_AND_DETACH}. This method invocation will fail silently when feature
* is not supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean explicitCallTransfer(BluetoothDevice device) {
if (DBG) log("explicitCallTransfer()");
final IBluetoothHeadsetClient service =
@@ -943,6 +965,7 @@
* successfully; <code>{@link null}</code> otherwise; upon completion HFP sends {@link
* #ACTION_CALL_CHANGED} intent in case of success; {@link #ACTION_RESULT} is sent otherwise;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
if (DBG) log("dial()");
final IBluetoothHeadsetClient service =
@@ -968,6 +991,7 @@
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_RESULT} intent;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendDTMF(BluetoothDevice device, byte code) {
if (DBG) log("sendDTMF()");
final IBluetoothHeadsetClient service =
@@ -1089,6 +1113,7 @@
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
getService();
@@ -1114,6 +1139,7 @@
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
getService();
@@ -1136,6 +1162,7 @@
* @param device remote device
* @return bundle of AG features; null if no service or AG not connected
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public Bundle getCurrentAgFeatures(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
getService();
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 5fd60e0..65f68a9 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -16,6 +16,10 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -111,8 +115,6 @@
* which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
* the callback is used to notify success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param name The friendly name associated with the application or configuration.
* @param dataType The dataType of the Source role of Health Profile to which the sink wants to
* connect to.
@@ -126,6 +128,10 @@
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean registerSinkAppConfiguration(String name, int dataType,
BluetoothHealthCallback callback) {
Log.e(TAG, "registerSinkAppConfiguration(): BluetoothHealth is deprecated");
@@ -136,8 +142,6 @@
* Unregister an application configuration that has been registered using
* {@link #registerSinkAppConfiguration}
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param config The health app configuration
* @return Success or failure.
*
@@ -147,6 +151,10 @@
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
Log.e(TAG, "unregisterAppConfiguration(): BluetoothHealth is deprecated");
return false;
@@ -157,8 +165,6 @@
* This is an asynchronous call. If this function returns true, the callback
* associated with the application configuration will be called.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote Bluetooth device.
* @param config The application configuration which has been registered using {@link
* #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
@@ -170,6 +176,10 @@
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean connectChannelToSource(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
Log.e(TAG, "connectChannelToSource(): BluetoothHealth is deprecated");
@@ -181,8 +191,6 @@
* This is an asynchronous call. If this function returns true, the callback
* associated with the application configuration will be called.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote Bluetooth device.
* @param config The application configuration which has been registered using {@link
* #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
@@ -195,6 +203,10 @@
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean disconnectChannel(BluetoothDevice device,
BluetoothHealthAppConfiguration config, int channelId) {
Log.e(TAG, "disconnectChannel(): BluetoothHealth is deprecated");
@@ -205,8 +217,6 @@
* Get the file descriptor of the main channel associated with the remote device
* and application configuration.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <p> Its the responsibility of the caller to close the ParcelFileDescriptor
* when done.
*
@@ -220,6 +230,10 @@
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
Log.e(TAG, "getMainChannelFd(): BluetoothHealth is deprecated");
@@ -229,8 +243,6 @@
/**
* Get the current connection state of the profile.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* This is not specific to any application configuration but represents the connection
* state of the local Bluetooth adapter with the remote device. This can be used
* by applications like status bar which would just like to know the state of the
@@ -241,6 +253,10 @@
* #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/
@Override
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public int getConnectionState(BluetoothDevice device) {
Log.e(TAG, "getConnectionState(): BluetoothHealth is deprecated");
return STATE_DISCONNECTED;
@@ -251,8 +267,6 @@
*
* <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* This is not specific to any application configuration but represents the connection
* state of the local Bluetooth adapter for this profile. This can be used
* by applications like status bar which would just like to know the state of the
@@ -261,6 +275,10 @@
* @return List of devices. The list will be empty on error.
*/
@Override
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public List<BluetoothDevice> getConnectedDevices() {
Log.e(TAG, "getConnectedDevices(): BluetoothHealth is deprecated");
return new ArrayList<>();
@@ -273,8 +291,7 @@
* <p> If none of the devices match any of the given states,
* an empty list will be returned.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- * This is not specific to any application configuration but represents the connection
+ * <p>This is not specific to any application configuration but represents the connection
* state of the local Bluetooth adapter for this profile. This can be used
* by applications like status bar which would just like to know the state of the
* local adapter.
@@ -284,6 +301,10 @@
* @return List of devices. The list will be empty on error.
*/
@Override
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Log.e(TAG, "getDevicesMatchingConnectionStates(): BluetoothHealth is deprecated");
return new ArrayList<>();
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index ff78825e..8ceeff5 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -22,6 +22,9 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -64,10 +67,10 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
@@ -81,11 +84,11 @@
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ACTIVE_DEVICE_CHANGED =
@@ -167,7 +170,10 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothHearingAid service = getService();
@@ -225,6 +231,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHearingAid service = getService();
@@ -244,6 +251,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
@NonNull int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
@@ -264,6 +272,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @BluetoothProfile.BtProfileState int getConnectionState(
@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
@@ -295,14 +304,14 @@
* {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
* with the active device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device the remote Bluetooth device. Could be null to clear
* the active device and stop streaming audio to a Bluetooth device.
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
@@ -330,7 +339,9 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getActiveDevices() {
if (VDBG) log("getActiveDevices()");
final IBluetoothHearingAid service = getService();
@@ -357,7 +368,10 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -376,7 +390,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -531,7 +548,7 @@
* @return SIDE_LEFT or SIDE_RIGHT
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public int getDeviceSide(BluetoothDevice device) {
if (VDBG) {
log("getDeviceSide(" + device + ")");
@@ -557,7 +574,7 @@
* @return MODE_MONAURAL or MODE_BINAURAL
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public int getDeviceMode(BluetoothDevice device) {
if (VDBG) {
log("getDeviceMode(" + device + ")");
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 2baa738..c214d2b 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -21,6 +21,8 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Binder;
@@ -56,9 +58,10 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link
* #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
* #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
@@ -436,6 +439,7 @@
/** {@inheritDoc} */
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
final IBluetoothHidDevice service = getService();
if (service != null) {
@@ -453,6 +457,7 @@
/** {@inheritDoc} */
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
final IBluetoothHidDevice service = getService();
if (service != null) {
@@ -470,6 +475,7 @@
/** {@inheritDoc} */
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
final IBluetoothHidDevice service = getService();
if (service != null) {
@@ -508,6 +514,7 @@
* object is required.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean registerApp(
BluetoothHidDeviceAppSdpSettings sdp,
BluetoothHidDeviceAppQosSettings inQos,
@@ -553,6 +560,7 @@
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean unregisterApp() {
boolean result = false;
@@ -578,6 +586,7 @@
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
boolean result = false;
@@ -604,6 +613,7 @@
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
boolean result = false;
@@ -628,6 +638,7 @@
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean reportError(BluetoothDevice device, byte error) {
boolean result = false;
@@ -651,6 +662,7 @@
* @return the current user name, or empty string if cannot get the name
* {@hide}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getUserAppName() {
final IBluetoothHidDevice service = getService();
@@ -675,6 +687,7 @@
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device) {
boolean result = false;
@@ -699,6 +712,7 @@
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
boolean result = false;
@@ -734,7 +748,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index 9561d93..70e3809 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -21,6 +21,9 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.Context;
@@ -65,11 +68,11 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
@SuppressLint("ActionValue")
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
@@ -328,7 +331,7 @@
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHidHost service = getService();
@@ -350,6 +353,7 @@
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHidHost service = getService();
@@ -372,7 +376,7 @@
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
if (device == null) {
@@ -503,12 +507,13 @@
/**
* Initiate virtual unplug for a HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean virtualUnplug(BluetoothDevice device) {
if (DBG) log("virtualUnplug(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -529,12 +534,13 @@
/**
* Send Get_Protocol_Mode command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getProtocolMode(BluetoothDevice device) {
if (VDBG) log("getProtocolMode(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -553,12 +559,13 @@
/**
* Send Set_Protocol_Mode command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
if (DBG) log("setProtocolMode(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -577,8 +584,6 @@
/**
* Send Get_Report command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param reportType Report type
* @param reportId Report ID
@@ -586,6 +591,9 @@
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
int bufferSize) {
if (VDBG) {
@@ -608,14 +616,15 @@
/**
* Send Set_Report command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param reportType Report type
* @param report Report receiving buffer size
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setReport(BluetoothDevice device, byte reportType, String report) {
if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
final IBluetoothHidHost service = getService();
@@ -634,13 +643,14 @@
/**
* Send Send_Data command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param report Report to send
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendData(BluetoothDevice device, String report) {
if (DBG) log("sendData(" + device + "), report=" + report);
final IBluetoothHidHost service = getService();
@@ -659,12 +669,13 @@
/**
* Send Get_Idle_Time command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getIdleTime(BluetoothDevice device) {
if (DBG) log("getIdletime(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -683,13 +694,14 @@
/**
* Send Set_Idle_Time command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param idleTime Idle time to be set on HID Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
final IBluetoothHidHost service = getService();
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 3f00fa6..4f095f6 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -23,6 +23,9 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -65,10 +68,10 @@
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED =
"android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
@@ -82,11 +85,11 @@
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED =
"android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
@@ -122,7 +125,6 @@
/**
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public void close() {
mProfileConnector.disconnect();
}
@@ -131,7 +133,6 @@
return mProfileConnector.getService();
}
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
protected void finalize() {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
@@ -154,7 +155,7 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(@Nullable BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
try {
@@ -193,7 +194,7 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(@Nullable BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
try {
@@ -213,6 +214,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
try {
@@ -232,6 +234,7 @@
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
@NonNull int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
@@ -252,7 +255,9 @@
* {@inheritDoc}
*/
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
try {
@@ -289,7 +294,7 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
try {
@@ -314,7 +319,7 @@
* @hide
*/
@NonNull
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public List<BluetoothDevice> getActiveDevices() {
if (VDBG) log("getActiveDevices()");
try {
@@ -337,7 +342,7 @@
* @return group id that this device currently belongs to
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public int getGroupId(@NonNull BluetoothDevice device) {
if (VDBG) log("getGroupId()");
try {
@@ -365,7 +370,10 @@
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -398,7 +406,7 @@
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
try {
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index d5c1c3e..a1e1b63 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -20,6 +20,8 @@
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.IBinder;
@@ -109,7 +111,9 @@
* {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED},
* {@link BluetoothProfile#STATE_DISCONNECTING}
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device, int profile) {
if (DBG) Log.d(TAG, "getConnectionState()");
@@ -136,7 +140,9 @@
* @param profile GATT or GATT_SERVER
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices(int profile) {
if (DBG) Log.d(TAG, "getConnectedDevices");
if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
@@ -177,7 +183,9 @@
* {@link BluetoothProfile#STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int profile, int[] states) {
if (DBG) Log.d(TAG, "getDevicesMatchingConnectionStates");
@@ -210,6 +218,7 @@
* @param callback GATT server callback handler that will receive asynchronous callbacks.
* @return BluetoothGattServer instance
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback) {
@@ -229,6 +238,7 @@
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, boolean eatt_support) {
return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO, eatt_support));
@@ -249,6 +259,7 @@
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, int transport) {
return (openGattServer(context, callback, transport, false));
@@ -270,6 +281,7 @@
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, int transport, boolean eatt_support) {
if (context == null || callback == null) {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 3554995..3e7b75a 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -93,7 +93,6 @@
mCloseGuard.open("close");
}
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
protected void finalize() {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
@@ -110,7 +109,6 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public void close() {
if (VDBG) log("close()");
mProfileConnector.disconnect();
@@ -128,6 +126,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getState() {
if (VDBG) log("getState()");
final IBluetoothMap service = getService();
@@ -152,6 +151,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getClient() {
if (VDBG) log("getClient()");
final IBluetoothMap service = getService();
@@ -175,6 +175,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")");
final IBluetoothMap service = getService();
@@ -211,6 +212,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothMap service = getService();
@@ -257,7 +259,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (DBG) log("getConnectedDevices()");
final IBluetoothMap service = getService();
@@ -280,6 +285,7 @@
*
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()");
final IBluetoothMap service = getService();
@@ -302,6 +308,7 @@
*
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")");
final IBluetoothMap service = getService();
@@ -328,7 +335,10 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -347,7 +357,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -378,7 +391,10 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -396,7 +412,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothMap service = getService();
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 0312a21..db74a90 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -192,6 +192,7 @@
* currently connected to the Map service.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -214,7 +215,10 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE");
final IBluetoothMapClient service = getService();
@@ -239,7 +243,10 @@
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean disconnect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "disconnect(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -261,6 +268,7 @@
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) Log.d(TAG, "getConnectedDevices()");
final IBluetoothMapClient service = getService();
@@ -283,6 +291,7 @@
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) Log.d(TAG, "getDevicesMatchingStates()");
final IBluetoothMapClient service = getService();
@@ -305,6 +314,7 @@
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getConnectionState(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -331,7 +341,10 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -349,7 +362,10 @@
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -380,7 +396,10 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -397,7 +416,10 @@
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -427,7 +449,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.SEND_SMS)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.SEND_SMS,
+ })
public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection<Uri> contacts,
@NonNull String message, @Nullable PendingIntent sentIntent,
@Nullable PendingIntent deliveredIntent) {
@@ -459,6 +484,10 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.SEND_SMS,
+ })
public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
PendingIntent sentIntent, PendingIntent deliveredIntent) {
if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
@@ -481,6 +510,10 @@
* @return true if the message is enqueued, false on error
* @hide
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.READ_SMS,
+ })
public boolean getUnreadMessages(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -503,6 +536,7 @@
* MapSupportedFeatures field is set. False is returned otherwise.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isUploadingSupported(BluetoothDevice device) {
final IBluetoothMapClient service = getService();
try {
@@ -530,7 +564,10 @@
* @return <code>true</code> if request has been sent, <code>false</code> on error
* @hide
*/
- @RequiresPermission(Manifest.permission.READ_SMS)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.READ_SMS,
+ })
public boolean setMessageStatus(BluetoothDevice device, String handle, int status) {
if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")");
final IBluetoothMapClient service = getService();
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index ecd718c..b3924b1f 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -22,6 +22,8 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -74,10 +76,11 @@
*
* <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or
* {@link #LOCAL_PANU_ROLE}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
@SuppressLint("ActionValue")
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
@@ -102,9 +105,10 @@
*
* <p> {@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or
* {@link #TETHERING_STATE_ON}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TETHERING_STATE_CHANGED =
"android.bluetooth.action.TETHERING_STATE_CHANGED";
@@ -236,6 +240,10 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothPan service = getService();
@@ -274,6 +282,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothPan service = getService();
@@ -302,7 +311,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -330,7 +342,10 @@
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothPan service = getService();
@@ -351,7 +366,12 @@
* @hide
*/
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothPan service = getService();
@@ -396,7 +416,11 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ })
public void setBluetoothTethering(boolean value) {
String pkgName = mContext.getOpPackageName();
if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
@@ -417,7 +441,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isTetheringOn() {
if (VDBG) log("isTetheringOn()");
final IBluetoothPan service = getService();
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 6e5c45f..6c2e5bf 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -22,6 +22,8 @@
import android.annotation.SdkConstant;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -82,8 +84,6 @@
* can be any of {@link BluetoothProfile#STATE_DISCONNECTED},
* {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED},
* {@link BluetoothProfile#STATE_DISCONNECTING}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*
* @hide
*/
@@ -142,6 +142,7 @@
doBind();
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
boolean doBind() {
synchronized (mConnection) {
try {
@@ -216,6 +217,7 @@
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
log("getConnectedDevices()");
final IBluetoothPbap service = mService;
@@ -262,6 +264,7 @@
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states));
final IBluetoothPbap service = mService;
@@ -294,7 +297,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -324,6 +330,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
log("disconnect()");
final IBluetoothPbap service = mService;
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index f356da1..2c8fbc2 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -160,6 +161,7 @@
* @return list of connected devices
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) {
log("getConnectedDevices()");
@@ -185,6 +187,7 @@
* @return list of matching devices
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) {
log("getDevicesMatchingStates()");
@@ -210,6 +213,7 @@
* @return device connection state
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) {
log("getConnectionState(" + device + ")");
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 201d6c4..70053ee 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-
package android.bluetooth;
-import android.Manifest;
import android.annotation.IntDef;
-import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -300,7 +297,6 @@
*
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
public List<BluetoothDevice> getConnectedDevices();
/**
@@ -314,7 +310,6 @@
* #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states);
/**
@@ -324,7 +319,6 @@
* @return State of the profile connection. One of {@link #STATE_CONNECTED}, {@link
* #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
@BtProfileState int getConnectionState(BluetoothDevice device);
/**
diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java
index 863fd36..12abcc4 100644
--- a/core/java/android/bluetooth/BluetoothProfileConnector.java
+++ b/core/java/android/bluetooth/BluetoothProfileConnector.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -78,6 +80,7 @@
mServiceName = serviceName;
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private boolean doBind() {
synchronized (mConnection) {
if (mService == null) {
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 0d70dbd..c85494c 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -18,6 +18,9 @@
import android.Manifest;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -61,11 +64,11 @@
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
@@ -140,6 +143,7 @@
* connected to the Sap service.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getState() {
if (VDBG) log("getState()");
final IBluetoothSap service = getService();
@@ -163,6 +167,7 @@
* this proxy object is not connected to the Sap service.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getClient() {
if (VDBG) log("getClient()");
final IBluetoothSap service = getService();
@@ -186,6 +191,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")");
final IBluetoothSap service = getService();
@@ -221,6 +227,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothSap service = getService();
@@ -242,6 +249,7 @@
* @return list of connected devices
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) log("getConnectedDevices()");
final IBluetoothSap service = getService();
@@ -263,6 +271,7 @@
* @return list of matching devices
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()");
final IBluetoothSap service = getService();
@@ -284,6 +293,7 @@
* @return device connection state
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")");
final IBluetoothSap service = getService();
@@ -310,7 +320,10 @@
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -328,7 +341,10 @@
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -359,7 +375,10 @@
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -376,7 +395,10 @@
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothSap service = getService();
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 5c1bcaf..5082235 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -62,9 +62,6 @@
* safe. In particular, {@link #close} will always immediately abort ongoing
* operations and close the server socket.
*
- * <p class="note"><strong>Note:</strong>
- * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using Bluetooth, read the
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 65381db..ef88147 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.LocalSocket;
import android.os.Build;
@@ -70,9 +72,6 @@
* safe. In particular, {@link #close} will always immediately abort ongoing
* operations and close the socket.
*
- * <p class="note"><strong>Note:</strong>
- * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using Bluetooth, read the
@@ -199,6 +198,7 @@
* @throws IOException On error, for example Bluetooth not available, or insufficient
* privileges
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
/*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)
throws IOException {
@@ -386,6 +386,7 @@
*
* @throws IOException on error, for example connection failure
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void connect() throws IOException {
if (mDevice == null) throw new IOException("Connect is called on null device");
@@ -427,6 +428,7 @@
* Currently returns unix errno instead of throwing IOException,
* so that BluetoothAdapter can check the error code for EADDRINUSE
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ int bindListen() {
int ret;
if (mSocketState == SocketState.CLOSED) return EBADFD;
@@ -682,6 +684,7 @@
* connection. This function is currently used for testing only.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void requestMaximumTxDataLength() throws IOException {
if (mDevice == null) {
throw new IOException("requestMaximumTxDataLength is called on null device");
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index 08d694e..d6868e0 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -830,7 +830,7 @@
@Nullable
@SystemApi
public byte[] getLeAppearance() {
- return mLeTemporaryKey;
+ return mLeAppearance;
}
/**
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java
new file mode 100644
index 0000000..c508c2c
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
+ * this requires the {@link Manifest.permission#BLUETOOTH_ADVERTISE}
+ * permission which can be gained with
+ * {@link android.app.Activity#requestPermissions(String[], int)}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothAdvertisePermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java
new file mode 100644
index 0000000..e159eaa
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
+ * this requires the {@link Manifest.permission#BLUETOOTH_CONNECT}
+ * permission which can be gained with
+ * {@link android.app.Activity#requestPermissions(String[], int)}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothConnectPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java
new file mode 100644
index 0000000..2bb3204
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc In addition, this requires either the
+ * {@link Manifest.permission#ACCESS_FINE_LOCATION}
+ * permission or a strong assertion that you will never derive the
+ * physical location of the device. You can make this assertion by
+ * declaring {@code usesPermissionFlags="neverForLocation"} on the
+ * relevant {@code <uses-permission>} manifest tag, but it may
+ * restrict the types of Bluetooth devices you can interact with.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothLocationPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java
new file mode 100644
index 0000000..800ff39
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
+ * this requires the {@link Manifest.permission#BLUETOOTH_SCAN}
+ * permission which can be gained with
+ * {@link android.app.Activity#requestPermissions(String[], int)}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothScanPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java
new file mode 100644
index 0000000..9adf695
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this
+ * requires the {@link Manifest.permission#BLUETOOTH_ADMIN}
+ * permission which can be gained with a simple
+ * {@code <uses-permission>} manifest tag.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresLegacyBluetoothAdminPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java
new file mode 100644
index 0000000..79621c3
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this
+ * requires the {@link Manifest.permission#BLUETOOTH} permission
+ * which can be gained with a simple {@code <uses-permission>}
+ * manifest tag.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresLegacyBluetoothPermission {
+}
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index 1df35e1..54a18e6 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -16,9 +16,12 @@
package android.bluetooth.le;
+import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.os.RemoteException;
import android.util.Log;
@@ -27,9 +30,6 @@
* <p>
* To get an instance of {@link AdvertisingSet}, call the
* {@link BluetoothLeAdvertiser#startAdvertisingSet} method.
- * <p>
- * <b>Note:</b> Most of the methods here require {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
*
* @see AdvertiseData
*/
@@ -58,8 +58,6 @@
/**
* Enables Advertising. This method returns immediately, the operation status is
* delivered through {@code callback.onAdvertisingEnabled()}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param enable whether the advertising should be enabled (true), or disabled (false)
* @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535
@@ -68,6 +66,9 @@
* controller shall attempt to send prior to terminating the extended advertising, even if the
* duration has not expired. Valid range is from 1 to 255.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void enableAdvertising(boolean enable, int duration,
int maxExtendedAdvertisingEvents) {
try {
@@ -90,6 +91,9 @@
* three bytes will be added for flags. If the update takes place when the advertising set is
* enabled, the data can be maximum 251 bytes long.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setAdvertisingData(AdvertiseData advertiseData) {
try {
mGatt.setAdvertisingData(mAdvertiserId, advertiseData);
@@ -107,6 +111,9 @@
* exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place
* when the advertising set is enabled, the data can be maximum 251 bytes long.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setScanResponseData(AdvertiseData scanResponse) {
try {
mGatt.setScanResponseData(mAdvertiserId, scanResponse);
@@ -122,6 +129,9 @@
*
* @param parameters advertising set parameters.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setAdvertisingParameters(AdvertisingSetParameters parameters) {
try {
mGatt.setAdvertisingParameters(mAdvertiserId, parameters);
@@ -135,6 +145,9 @@
* periodic advertising is not enabled. This method returns immediately, the operation
* status is delivered through {@code callback.onPeriodicAdvertisingParametersUpdated()}.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingParameters(PeriodicAdvertisingParameters parameters) {
try {
mGatt.setPeriodicAdvertisingParameters(mAdvertiserId, parameters);
@@ -153,6 +166,9 @@
* BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place when the
* periodic advertising is enabled for this set, the data can be maximum 251 bytes long.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingData(AdvertiseData periodicData) {
try {
mGatt.setPeriodicAdvertisingData(mAdvertiserId, periodicData);
@@ -168,6 +184,9 @@
* @param enable whether the periodic advertising should be enabled (true), or disabled
* (false).
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingEnabled(boolean enable) {
try {
mGatt.setPeriodicAdvertisingEnable(mAdvertiserId, enable);
@@ -181,10 +200,9 @@
* This method is exposed only for Bluetooth PTS tests, no app or system service
* should ever use it.
*
- * This method requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
- *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void getOwnAddress() {
try {
mGatt.getOwnAddress(mAdvertiserId);
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 5f166f4..de11869 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -16,11 +16,15 @@
package android.bluetooth.le;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
@@ -38,9 +42,6 @@
* <p>
* To get an instance of {@link BluetoothLeAdvertiser}, call the
* {@link BluetoothAdapter#getBluetoothLeAdvertiser()} method.
- * <p>
- * <b>Note:</b> Most of the methods here require {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
*
* @see AdvertiseData
*/
@@ -81,13 +82,17 @@
/**
* Start Bluetooth LE Advertising. On success, the {@code advertiseData} will be broadcasted.
* Returns immediately, the operation status is delivered through {@code callback}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @param settings Settings for Bluetooth LE advertising.
* @param advertiseData Advertisement data to be broadcasted.
* @param callback Callback for advertising status.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, final AdvertiseCallback callback) {
startAdvertising(settings, advertiseData, null, callback);
@@ -98,14 +103,18 @@
* operation succeeds. The {@code scanResponse} is returned when a scanning device sends an
* active scan request. This method returns immediately, the operation status is delivered
* through {@code callback}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param settings Settings for Bluetooth LE advertising.
* @param advertiseData Advertisement data to be advertised in advertisement packet.
* @param scanResponse Scan response associated with the advertisement data.
* @param callback Callback for advertising status.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, AdvertiseData scanResponse,
final AdvertiseCallback callback) {
@@ -160,9 +169,11 @@
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) {
return new AdvertisingSetCallback() {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
int status) {
if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
@@ -175,6 +186,7 @@
/* Legacy advertiser is disabled on timeout */
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enabled,
int status) {
if (enabled) {
@@ -192,11 +204,12 @@
/**
* Stop Bluetooth LE advertising. The {@code callback} must be the same one use in
* {@link BluetoothLeAdvertiser#startAdvertising}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @param callback {@link AdvertiseCallback} identifies the advertising instance to stop.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void stopAdvertising(final AdvertiseCallback callback) {
synchronized (mLegacyAdvertisers) {
if (callback == null) {
@@ -232,6 +245,12 @@
* size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
* feature is made when it's not supported by the controller.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -262,6 +281,12 @@
* size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
* feature is made when it's not supported by the controller.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -297,6 +322,12 @@
* size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
* feature is made when it's not supported by the controller.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -337,6 +368,12 @@
* maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended
* Advertising
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -445,6 +482,9 @@
* Used to dispose of a {@link AdvertisingSet} object, obtained with {@link
* BluetoothLeAdvertiser#startAdvertisingSet}.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void stopAdvertisingSet(AdvertisingSetCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
@@ -476,6 +516,7 @@
}
// Compute the size of advertisement data or scan resp
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private int totalBytes(AdvertiseData data, boolean isFlagsIncluded) {
if (data == null) return 0;
// Flags field is omitted if the advertising is not connectable.
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 2601cd4..4271a90 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -20,12 +20,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.content.AttributionSource;
import android.os.Handler;
import android.os.Looper;
@@ -45,9 +49,6 @@
* <p>
* Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of
* {@link BluetoothLeScanner}.
- * <p>
- * <b>Note:</b> Most of the scan methods here require
- * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @see ScanFilter
*/
@@ -117,7 +118,10 @@
* @param callback Callback used to deliver scan results.
* @throws IllegalArgumentException If {@code callback} is null.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startScan(final ScanCallback callback) {
startScan(null, new ScanSettings.Builder().build(), callback);
}
@@ -139,7 +143,10 @@
* @param callback Callback used to deliver scan results.
* @throws IllegalArgumentException If {@code settings} or {@code callback} is null.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startScan(List<ScanFilter> filters, ScanSettings settings,
final ScanCallback callback) {
startScan(filters, settings, null, callback, /*callbackIntent=*/ null, null);
@@ -168,7 +175,10 @@
* could not be sent.
* @see #stopScan(PendingIntent)
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings,
@NonNull PendingIntent callbackIntent) {
return startScan(filters,
@@ -186,8 +196,13 @@
* @hide
*/
@SystemApi
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
@RequiresPermission(allOf = {
- Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS})
+ android.Manifest.permission.BLUETOOTH_SCAN,
+ android.Manifest.permission.UPDATE_DEVICE_STATS
+ })
public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) {
startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback);
}
@@ -204,13 +219,20 @@
* @hide
*/
@SystemApi
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
@RequiresPermission(allOf = {
- Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS})
+ android.Manifest.permission.BLUETOOTH_SCAN,
+ android.Manifest.permission.UPDATE_DEVICE_STATS
+ })
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback) {
startScan(filters, settings, workSource, callback, null, null);
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
private int startScan(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback,
final PendingIntent callbackIntent,
@@ -268,7 +290,9 @@
*
* @param callback
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopScan(ScanCallback callback) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
synchronized (mLeScanClients) {
@@ -289,7 +313,9 @@
* @param callbackIntent The PendingIntent that was used to start the scan.
* @see #startScan(List, ScanSettings, PendingIntent)
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopScan(PendingIntent callbackIntent) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
IBluetoothGatt gatt;
@@ -308,6 +334,9 @@
* @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one
* used to start scan.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void flushPendingScanResults(ScanCallback callback) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
if (callback == null) {
@@ -328,6 +357,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings,
final ScanCallback callback) {
int filterSize = truncatedFilters.size();
@@ -382,6 +412,8 @@
mResultStorages = resultStorages;
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startRegistration() {
synchronized (this) {
// Scan stopped.
@@ -409,6 +441,8 @@
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopLeScan() {
synchronized (this) {
if (mScannerId <= 0) {
@@ -425,6 +459,8 @@
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
void flushPendingBatchResults() {
synchronized (this) {
if (mScannerId <= 0) {
@@ -443,6 +479,7 @@
* Application interface registered - app is ready to go
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onScannerRegistered(int status, int scannerId) {
Log.d(TAG, "onScannerRegistered() - status=" + status
+ " scannerId=" + scannerId + " mScannerId=" + mScannerId);
@@ -595,6 +632,7 @@
return true;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) {
final int callbackType = settings.getCallbackType();
if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
index 0f1a8e9..9ea6c48 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
@@ -16,10 +16,14 @@
package android.bluetooth.le;
+import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -35,9 +39,6 @@
* <p>
* Use {@link BluetoothAdapter#getPeriodicAdvertisingManager()} to get an
* instance of {@link PeriodicAdvertisingManager}.
- * <p>
- * <b>Note:</b> Most of the methods here require
- * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @hide
*/
@@ -89,6 +90,10 @@
* @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or
* {@code timeout} is invalid or {@code callback} is null.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void registerSync(ScanResult scanResult, int skip, int timeout,
PeriodicAdvertisingCallback callback) {
registerSync(scanResult, skip, timeout, callback, null);
@@ -113,6 +118,10 @@
* @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or
* {@code timeout} is invalid or {@code callback} is null.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void registerSync(ScanResult scanResult, int skip, int timeout,
PeriodicAdvertisingCallback callback, Handler handler) {
if (callback == null) {
@@ -170,6 +179,9 @@
* @throws IllegalArgumentException if {@code callback} is null, or not a properly registered
* callback.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void unregisterSync(PeriodicAdvertisingCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback can't be null");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 09ac810..318913f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2208,6 +2208,17 @@
}
/**
+ * Like {@link #sendBroadcastMultiplePermissions(Intent, String[])}, but also allows
+ * specification of a list of excluded permissions. This allows sending a broadcast to an
+ * app that has the permissions in `receiverPermissions` but not `excludedPermissions`.
+ * @hide
+ */
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Broadcast the given intent to all interested BroadcastReceivers, allowing
* an array of required permissions to be enforced. This call is asynchronous; it returns
* immediately, and you will continue executing while the receivers are run. No results are
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 8936d0c..dddcbea 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -493,6 +493,13 @@
/** @hide */
@Override
+ public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+ @NonNull String[] receiverPermissions, @Nullable String[] excludedPermissions) {
+ mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions, excludedPermissions);
+ }
+
+ /** @hide */
+ @Override
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
String[] receiverPermissions) {
mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9ad017c..f8d407d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2871,6 +2871,7 @@
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_FULLY_LOADED =
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index 6d5829c..eb50924 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -52,7 +52,7 @@
/** The name of the schema type for {@link ShortcutInfo} documents.*/
public static final String SCHEMA_TYPE = "Shortcut";
- public static final int SCHEMA_VERSION = 1;
+ public static final int SCHEMA_VERSION = 2;
public static final String KEY_ACTIVITY = "activity";
public static final String KEY_SHORT_LABEL = "shortLabel";
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5ff1124..86a8a9d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -8923,6 +8923,8 @@
private final @ParseFlags int mFlags;
private AssetManager mCachedAssetManager;
+ private ApkAssets mBaseApkAssets;
+
DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags) {
mBaseCodePath = pkg.baseCodePath;
mSplitCodePaths = pkg.splitCodePaths;
@@ -8953,9 +8955,11 @@
ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null
? mSplitCodePaths.length : 0) + 1];
+ mBaseApkAssets = loadApkAssets(mBaseCodePath, mFlags);
+
// Load the base.
int splitIdx = 0;
- apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags);
+ apkAssets[splitIdx++] = mBaseApkAssets;
// Load any splits.
if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
@@ -8982,6 +8986,11 @@
public void close() throws Exception {
IoUtils.closeQuietly(mCachedAssetManager);
}
+
+ @Override
+ public ApkAssets getBaseApkAssets() {
+ return mBaseApkAssets;
+ }
}
/**
@@ -9085,5 +9094,10 @@
IoUtils.closeQuietly(assets);
}
}
+
+ @Override
+ public ApkAssets getBaseApkAssets() {
+ return mCachedSplitApks[0][0];
+ }
}
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index a1ffc0c..0fc6b2b 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -383,10 +383,9 @@
}
try {
- final AssetManager assets = assetLoader.getBaseAssetManager();
final File baseApk = new File(lite.getBaseApkPath());
final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
- lite.getPath(), assets, flags);
+ lite.getPath(), assetLoader, flags);
if (result.isError()) {
return input.error(result);
}
@@ -442,7 +441,7 @@
final ParseResult<ParsingPackage> result = parseBaseApk(input,
apkFile,
apkFile.getCanonicalPath(),
- assetLoader.getBaseAssetManager(), flags);
+ assetLoader, flags);
if (result.isError()) {
return input.error(result);
}
@@ -458,7 +457,8 @@
}
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
- String codePath, AssetManager assets, int flags) {
+ String codePath, SplitAssetLoader assetLoader, int flags)
+ throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
@@ -469,6 +469,7 @@
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
+ final AssetManager assets = assetLoader.getBaseAssetManager();
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
@@ -500,12 +501,19 @@
}
}
- ApkAssets apkAssets = assets.getApkAssets()[0];
- if (apkAssets.definesOverlayable()) {
+ ApkAssets apkAssets = assetLoader.getBaseApkAssets();
+ boolean definesOverlayable = false;
+ try {
+ definesOverlayable = apkAssets.definesOverlayable();
+ } catch (IOException ignored) {
+ // Will fail if there's no packages in the ApkAssets, which can be treated as false
+ }
+
+ if (definesOverlayable) {
SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
int size = packageNames.size();
for (int index = 0; index < size; index++) {
- String packageName = packageNames.get(index);
+ String packageName = packageNames.valueAt(index);
Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
for (String overlayable : overlayableToActor.keySet()) {
@@ -2799,7 +2807,15 @@
}
}
+ @SuppressWarnings("AndroidFrameworkCompatChange")
private void convertSplitPermissions(ParsingPackage pkg) {
+ // STOPSHIP(b/183905675): REMOVE THIS TERRIBLE, HORRIBLE, NO GOOD, VERY BAD HACK
+ if ("com.android.chrome".equals(pkg.getPackageName())
+ && pkg.getVersionCode() <= 445500399
+ && pkg.getTargetSdkVersion() > Build.VERSION_CODES.R) {
+ pkg.setTargetSdkVersion(Build.VERSION_CODES.R);
+ }
+
final int listSize = mSplitPermissionInfos.size();
for (int is = 0; is < listSize; is++) {
final PermissionManager.SplitPermissionInfo spi = mSplitPermissionInfos.get(is);
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttribution.java b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
index 3a4aae1..4ec2e73 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+++ b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
@@ -40,7 +40,7 @@
public static final int MAX_ATTRIBUTION_TAG_LEN = 50;
/** Maximum amount of attributions per package */
- private static final int MAX_NUM_ATTRIBUTIONS = 1000;
+ private static final int MAX_NUM_ATTRIBUTIONS = 10000;
/** Tag of the attribution */
public final @NonNull String tag;
@@ -100,7 +100,7 @@
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -215,8 +215,8 @@
};
@DataClass.Generated(
- time = 1607463855175L,
- codegenVersion = "1.0.22",
+ time = 1618351459610L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java",
inputSignatures = "public static final int MAX_ATTRIBUTION_TAG_LEN\nprivate static final int MAX_NUM_ATTRIBUTIONS\npublic final @android.annotation.NonNull java.lang.String tag\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
@Deprecated
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
index f3caf60..c1a8396 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -43,6 +43,8 @@
private final @ParseFlags int mFlags;
private AssetManager mCachedAssetManager;
+ private ApkAssets mBaseApkAssets;
+
public DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags) {
mBaseApkPath = pkg.getBaseApkPath();
mSplitApkPaths = pkg.getSplitApkPaths();
@@ -76,7 +78,7 @@
// Load the base.
int splitIdx = 0;
- apkAssets[splitIdx++] = loadApkAssets(mBaseApkPath, mFlags);
+ apkAssets[splitIdx++] = mBaseApkAssets = loadApkAssets(mBaseApkPath, mFlags);
// Load any splits.
if (!ArrayUtils.isEmpty(mSplitApkPaths)) {
@@ -100,6 +102,11 @@
}
@Override
+ public ApkAssets getBaseApkAssets() {
+ return mBaseApkAssets;
+ }
+
+ @Override
public void close() throws Exception {
IoUtils.closeQuietly(mCachedAssetManager);
}
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 523ca40..e5c2158 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -128,6 +128,11 @@
}
@Override
+ public ApkAssets getBaseApkAssets() {
+ return mCachedSplitApks[0][0];
+ }
+
+ @Override
public void close() throws Exception {
for (AssetManager assets : mCachedAssetManagers) {
IoUtils.closeQuietly(assets);
diff --git a/core/java/android/content/pm/split/SplitAssetLoader.java b/core/java/android/content/pm/split/SplitAssetLoader.java
index 108fb95..7584e15f 100644
--- a/core/java/android/content/pm/split/SplitAssetLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetLoader.java
@@ -16,6 +16,7 @@
package android.content.pm.split;
import android.content.pm.PackageParser;
+import android.content.res.ApkAssets;
import android.content.res.AssetManager;
/**
@@ -27,4 +28,6 @@
public interface SplitAssetLoader extends AutoCloseable {
AssetManager getBaseAssetManager() throws PackageParser.PackageParserException;
AssetManager getSplitAssetManager(int splitIdx) throws PackageParser.PackageParserException;
+
+ ApkAssets getBaseApkAssets();
}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
index 33920c6..77bd147 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
@@ -32,8 +32,12 @@
import com.android.internal.util.CollectionUtils;
+import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.UUID;
/**
@@ -346,17 +350,24 @@
* an Intent with that domain. That will be decided by the set of apps which
* are the highest priority level, ignoring all lower priority levels.
*
- * By default the list will be returned ordered from lowest to highest
- * priority.
+ * The set will be ordered from lowest to highest priority.
+ *
+ * @param domain The host to query for. An invalid domain will result in an empty set.
*
* @hide
*/
@SystemApi
@NonNull
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
- public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
+ public SortedSet<DomainOwner> getOwnersForDomain(@NonNull String domain) {
try {
- return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
+ Objects.requireNonNull(domain);
+ final List<DomainOwner> orderedList = mDomainVerificationManager.getOwnersForDomain(
+ domain, mContext.getUserId());
+ SortedSet<DomainOwner> set = new TreeSet<>(
+ Comparator.comparingInt(orderedList::indexOf));
+ set.addAll(orderedList);
+ return set;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 3c11d8e..bc2dcb3 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -571,10 +571,10 @@
}
int sensorHandle = (sensor == null) ? -1 : sensor.getHandle();
- if (Compatibility.isChangeEnabled(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION)
- && rate > CAPPED_SAMPLING_RATE_LEVEL
+ if (rate > CAPPED_SAMPLING_RATE_LEVEL
&& mIsPackageDebuggable
- && !mHasHighSamplingRateSensorsPermission) {
+ && !mHasHighSamplingRateSensorsPermission
+ && Compatibility.isChangeEnabled(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION)) {
throw new SecurityException("To use the sampling rate level " + rate
+ ", app needs to declare the normal permission"
+ " HIGH_SAMPLING_RATE_SENSORS.");
@@ -782,10 +782,10 @@
Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
if (mNativeSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
- if (Compatibility.isChangeEnabled(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION)
- && rateUs < CAPPED_SAMPLING_PERIOD_US
+ if (rateUs < CAPPED_SAMPLING_PERIOD_US
&& mManager.mIsPackageDebuggable
- && !mManager.mHasHighSamplingRateSensorsPermission) {
+ && !mManager.mHasHighSamplingRateSensorsPermission
+ && Compatibility.isChangeEnabled(CHANGE_ID_SAMPLING_RATE_SENSORS_PERMISSION)) {
throw new SecurityException("To use the sampling rate of " + rateUs
+ " microseconds, app needs to declare the normal permission"
+ " HIGH_SAMPLING_RATE_SENSORS.");
diff --git a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
index 62d727c..1268658 100644
--- a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
@@ -16,11 +16,9 @@
package android.hardware.biometrics;
-import android.hardware.biometrics.BiometricSourceType;
-
/**
* @hide
*/
oneway interface IBiometricEnabledOnKeyguardCallback {
- void onChanged(in BiometricSourceType type, boolean enabled, int userId);
+ void onChanged(boolean enabled, int userId);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 11c426a..835b3fd 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -74,12 +74,26 @@
Integer modelYear,
ManufactureDate manufactureDate,
int connectionToSinkType) {
- this.mName = name;
- this.mManufacturerPnpId = manufacturerPnpId;
- this.mProductId = productId;
- this.mModelYear = modelYear;
- this.mManufactureDate = manufactureDate;
- this.mConnectionToSinkType = connectionToSinkType;
+ mName = name;
+ mManufacturerPnpId = manufacturerPnpId;
+ mProductId = productId;
+ mModelYear = modelYear;
+ mManufactureDate = manufactureDate;
+ mConnectionToSinkType = connectionToSinkType;
+ }
+
+ public DeviceProductInfo(
+ @Nullable String name,
+ @NonNull String manufacturerPnpId,
+ @NonNull String productId,
+ @IntRange(from = 1990) int modelYear,
+ @ConnectionToSinkType int connectionToSinkType) {
+ mName = name;
+ mManufacturerPnpId = Objects.requireNonNull(manufacturerPnpId);
+ mProductId = Objects.requireNonNull(productId);
+ mModelYear = modelYear;
+ mManufactureDate = null;
+ mConnectionToSinkType = connectionToSinkType;
}
private DeviceProductInfo(Parcel in) {
@@ -100,6 +114,9 @@
}
/**
+ * Returns the Manufacturer Plug and Play ID. This ID identifies the manufacture according to
+ * the list: https://uefi.org/PNP_ID_List. It consist of 3 characters, each character
+ * is an uppercase letter (A-Z).
* @return Manufacturer Plug and Play ID.
*/
@NonNull
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 5f65d46..662ebb3 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -78,10 +78,8 @@
/**
* An IPsec VPN created by the built-in LegacyVpnRunner.
- * @deprecated new Android devices should use VPN_TYPE_PLATFORM instead.
* @hide
*/
- @Deprecated
@SystemApi(client = MODULE_LIBRARIES)
public static final int TYPE_VPN_LEGACY = 3;
@@ -418,4 +416,4 @@
throw e.rethrowFromSystemServer();
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 75db3820..d7c6fa1 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -79,7 +79,12 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int MIN_MTU_V6 = 1280;
- private static final Set<Integer> ALLOWED_CAPABILITIES;
+ /**
+ * The set of allowed capabilities for exposed capabilities.
+ *
+ * @hide
+ */
+ public static final Set<Integer> ALLOWED_CAPABILITIES;
static {
Set<Integer> allowedCaps = new ArraySet<>();
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index d5cc01a..cb9a3e4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -24,7 +24,7 @@
import android.nfc.TechListParcel;
import android.nfc.IAppCallback;
import android.nfc.INfcAdapterExtras;
-import android.nfc.INfcControllerAlwaysOnStateCallback;
+import android.nfc.INfcControllerAlwaysOnListener;
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
import android.nfc.INfcFCardEmulation;
@@ -76,6 +76,6 @@
boolean setControllerAlwaysOn(boolean value);
boolean isControllerAlwaysOn();
boolean isControllerAlwaysOnSupported();
- void registerControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
- void unregisterControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
+ void registerControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
+ void unregisterControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/core/java/android/nfc/INfcControllerAlwaysOnListener.aidl
similarity index 87%
rename from core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
rename to core/java/android/nfc/INfcControllerAlwaysOnListener.aidl
index 1e4fdd7..1bb7680 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
+++ b/core/java/android/nfc/INfcControllerAlwaysOnListener.aidl
@@ -19,11 +19,11 @@
/**
* @hide
*/
-oneway interface INfcControllerAlwaysOnStateCallback {
+oneway interface INfcControllerAlwaysOnListener {
/**
* Called whenever the controller always on state changes
*
* @param isEnabled true if the state is enabled, false otherwise
*/
- void onControllerAlwaysOnStateChanged(boolean isEnabled);
+ void onControllerAlwaysOnChanged(boolean isEnabled);
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index bbf802c..64c1211 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -67,7 +67,7 @@
public final class NfcAdapter {
static final String TAG = "NFC";
- private final NfcControllerAlwaysOnStateListener mControllerAlwaysOnStateListener;
+ private final NfcControllerAlwaysOnListener mControllerAlwaysOnListener;
/**
* Intent to start an activity when a tag with NDEF payload is discovered.
@@ -418,19 +418,19 @@
}
/**
- * A callback to be invoked when NFC controller always on state changes.
- * <p>Register your {@code ControllerAlwaysOnStateCallback} implementation with {@link
- * NfcAdapter#registerControllerAlwaysOnStateCallback} and disable it with {@link
- * NfcAdapter#unregisterControllerAlwaysOnStateCallback}.
- * @see #registerControllerAlwaysOnStateCallback
+ * A listener to be invoked when NFC controller always on state changes.
+ * <p>Register your {@code ControllerAlwaysOnListener} implementation with {@link
+ * NfcAdapter#registerControllerAlwaysOnListener} and disable it with {@link
+ * NfcAdapter#unregisterControllerAlwaysOnListener}.
+ * @see #registerControllerAlwaysOnListener
* @hide
*/
@SystemApi
- public interface ControllerAlwaysOnStateCallback {
+ public interface ControllerAlwaysOnListener {
/**
* Called on NFC controller always on state changes
*/
- void onStateChanged(boolean isEnabled);
+ void onControllerAlwaysOnChanged(boolean isEnabled);
}
/**
@@ -748,7 +748,7 @@
mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
mTagRemovedListener = null;
mLock = new Object();
- mControllerAlwaysOnStateListener = new NfcControllerAlwaysOnStateListener(getService());
+ mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
}
/**
@@ -2246,12 +2246,12 @@
* <p>This API is for the NFCC internal state management. It allows to discriminate
* the controller function from the NFC function by keeping the NFC controller on without
* any NFC RF enabled if necessary.
- * <p>This call is asynchronous. Register a callback {@link #ControllerAlwaysOnStateCallback}
- * by {@link #registerControllerAlwaysOnStateCallback} to find out when the operation is
+ * <p>This call is asynchronous. Register a listener {@link #ControllerAlwaysOnListener}
+ * by {@link #registerControllerAlwaysOnListener} to find out when the operation is
* complete.
* <p>If this returns true, then either NFCC always on state has been set based on the value,
- * or a {@link ControllerAlwaysOnStateCallback#onStateChanged(boolean)} will be invoked to
- * indicate the state change.
+ * or a {@link ControllerAlwaysOnListener#onControllerAlwaysOnChanged(boolean)} will be invoked
+ * to indicate the state change.
* If this returns false, then there is some problem that prevents an attempt to turn NFCC
* always on.
* @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
@@ -2344,37 +2344,37 @@
}
/**
- * Register a {@link ControllerAlwaysOnStateCallback} to listen for NFC controller always on
+ * Register a {@link ControllerAlwaysOnListener} to listen for NFC controller always on
* state changes
- * <p>The provided callback will be invoked by the given {@link Executor}.
+ * <p>The provided listener will be invoked by the given {@link Executor}.
*
- * @param executor an {@link Executor} to execute given callback
- * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ * @param executor an {@link Executor} to execute given listener
+ * @param listener user implementation of the {@link ControllerAlwaysOnListener}
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public void registerControllerAlwaysOnStateCallback(
+ public void registerControllerAlwaysOnListener(
@NonNull @CallbackExecutor Executor executor,
- @NonNull ControllerAlwaysOnStateCallback callback) {
- mControllerAlwaysOnStateListener.register(executor, callback);
+ @NonNull ControllerAlwaysOnListener listener) {
+ mControllerAlwaysOnListener.register(executor, listener);
}
/**
- * Unregister the specified {@link ControllerAlwaysOnStateCallback}
- * <p>The same {@link ControllerAlwaysOnStateCallback} object used when calling
- * {@link #registerControllerAlwaysOnStateCallback(Executor, ControllerAlwaysOnStateCallback)}
+ * Unregister the specified {@link ControllerAlwaysOnListener}
+ * <p>The same {@link ControllerAlwaysOnListener} object used when calling
+ * {@link #registerControllerAlwaysOnListener(Executor, ControllerAlwaysOnListener)}
* must be used.
*
- * <p>Callbacks are automatically unregistered when application process goes away
+ * <p>Listeners are automatically unregistered when application process goes away
*
- * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ * @param listener user implementation of the {@link ControllerAlwaysOnListener}
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public void unregisterControllerAlwaysOnStateCallback(
- @NonNull ControllerAlwaysOnStateCallback callback) {
- mControllerAlwaysOnStateListener.unregister(callback);
+ public void unregisterControllerAlwaysOnListener(
+ @NonNull ControllerAlwaysOnListener listener) {
+ mControllerAlwaysOnListener.unregister(listener);
}
}
diff --git a/core/java/android/nfc/NfcControllerAlwaysOnListener.java b/core/java/android/nfc/NfcControllerAlwaysOnListener.java
new file mode 100644
index 0000000..96707bb
--- /dev/null
+++ b/core/java/android/nfc/NfcControllerAlwaysOnListener.java
@@ -0,0 +1,120 @@
+/*
+ * 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.nfc;
+
+import android.annotation.NonNull;
+import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class NfcControllerAlwaysOnListener extends INfcControllerAlwaysOnListener.Stub {
+ private static final String TAG = NfcControllerAlwaysOnListener.class.getSimpleName();
+
+ private final INfcAdapter mAdapter;
+
+ private final Map<ControllerAlwaysOnListener, Executor> mListenerMap = new HashMap<>();
+
+ private boolean mCurrentState = false;
+ private boolean mIsRegistered = false;
+
+ public NfcControllerAlwaysOnListener(@NonNull INfcAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Register a {@link ControllerAlwaysOnListener} with this
+ * {@link NfcControllerAlwaysOnListener}
+ *
+ * @param executor an {@link Executor} to execute given listener
+ * @param listener user implementation of the {@link ControllerAlwaysOnListener}
+ */
+ public void register(@NonNull Executor executor,
+ @NonNull ControllerAlwaysOnListener listener) {
+ synchronized (this) {
+ if (mListenerMap.containsKey(listener)) {
+ return;
+ }
+
+ mListenerMap.put(listener, executor);
+ if (!mIsRegistered) {
+ try {
+ mAdapter.registerControllerAlwaysOnListener(this);
+ mIsRegistered = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to register");
+ }
+ }
+ }
+ }
+
+ /**
+ * Unregister the specified {@link ControllerAlwaysOnListener}
+ *
+ * @param listener user implementation of the {@link ControllerAlwaysOnListener}
+ */
+ public void unregister(@NonNull ControllerAlwaysOnListener listener) {
+ synchronized (this) {
+ if (!mListenerMap.containsKey(listener)) {
+ return;
+ }
+
+ mListenerMap.remove(listener);
+
+ if (mListenerMap.isEmpty() && mIsRegistered) {
+ try {
+ mAdapter.unregisterControllerAlwaysOnListener(this);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to unregister");
+ }
+ mIsRegistered = false;
+ }
+ }
+ }
+
+ private void sendCurrentState(@NonNull ControllerAlwaysOnListener listener) {
+ synchronized (this) {
+ Executor executor = mListenerMap.get(listener);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> listener.onControllerAlwaysOnChanged(
+ mCurrentState));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onControllerAlwaysOnChanged(boolean isEnabled) {
+ synchronized (this) {
+ mCurrentState = isEnabled;
+ for (ControllerAlwaysOnListener cb : mListenerMap.keySet()) {
+ sendCurrentState(cb);
+ }
+ }
+ }
+}
+
diff --git a/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java b/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
deleted file mode 100644
index 69a9ec7..0000000
--- a/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.nfc;
-
-import android.annotation.NonNull;
-import android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public class NfcControllerAlwaysOnStateListener extends INfcControllerAlwaysOnStateCallback.Stub {
- private static final String TAG = "NfcControllerAlwaysOnStateListener";
-
- private final INfcAdapter mAdapter;
-
- private final Map<ControllerAlwaysOnStateCallback, Executor> mCallbackMap = new HashMap<>();
-
- private boolean mCurrentState = false;
- private boolean mIsRegistered = false;
-
- public NfcControllerAlwaysOnStateListener(@NonNull INfcAdapter adapter) {
- mAdapter = adapter;
- }
-
- /**
- * Register a {@link ControllerAlwaysOnStateCallback} with this
- * {@link NfcControllerAlwaysOnStateListener}
- *
- * @param executor an {@link Executor} to execute given callback
- * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
- */
- public void register(@NonNull Executor executor,
- @NonNull ControllerAlwaysOnStateCallback callback) {
- synchronized (this) {
- if (mCallbackMap.containsKey(callback)) {
- return;
- }
-
- mCallbackMap.put(callback, executor);
- if (!mIsRegistered) {
- try {
- mAdapter.registerControllerAlwaysOnStateCallback(this);
- mIsRegistered = true;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to register ControllerAlwaysOnStateListener");
- }
- }
- }
- }
-
- /**
- * Unregister the specified {@link ControllerAlwaysOnStateCallback}
- *
- * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
- */
- public void unregister(@NonNull ControllerAlwaysOnStateCallback callback) {
- synchronized (this) {
- if (!mCallbackMap.containsKey(callback)) {
- return;
- }
-
- mCallbackMap.remove(callback);
-
- if (mCallbackMap.isEmpty() && mIsRegistered) {
- try {
- mAdapter.unregisterControllerAlwaysOnStateCallback(this);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to unregister ControllerAlwaysOnStateListener");
- }
- mIsRegistered = false;
- }
- }
- }
-
- private void sendCurrentState(@NonNull ControllerAlwaysOnStateCallback callback) {
- synchronized (this) {
- Executor executor = mCallbackMap.get(callback);
-
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> callback.onStateChanged(
- mCurrentState));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- @Override
- public void onControllerAlwaysOnStateChanged(boolean isEnabled) {
- synchronized (this) {
- mCurrentState = isEnabled;
- for (ControllerAlwaysOnStateCallback cb : mCallbackMap.keySet()) {
- sendCurrentState(cb);
- }
- }
- }
-}
-
diff --git a/core/java/android/nfc/TEST_MAPPING b/core/java/android/nfc/TEST_MAPPING
new file mode 100644
index 0000000..71ad687
--- /dev/null
+++ b/core/java/android/nfc/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "NfcManagerTests"
+ }
+ ]
+}
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 0331483..ba63ba4 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -36,7 +36,7 @@
* @hide
*/
@IntDef(prefix = {"POWER_COMPONENT_"}, value = {
- POWER_COMPONENT_USAGE,
+ POWER_COMPONENT_SCREEN,
POWER_COMPONENT_CPU,
POWER_COMPONENT_BLUETOOTH,
POWER_COMPONENT_CAMERA,
@@ -49,14 +49,16 @@
POWER_COMPONENT_GNSS,
POWER_COMPONENT_WIFI,
POWER_COMPONENT_WAKELOCK,
- POWER_COMPONENT_SCREEN,
+ POWER_COMPONENT_MEMORY,
+ POWER_COMPONENT_PHONE,
+ POWER_COMPONENT_IDLE,
POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface PowerComponent {
}
- public static final int POWER_COMPONENT_USAGE = 0;
+ public static final int POWER_COMPONENT_SCREEN = 0;
public static final int POWER_COMPONENT_CPU = 1;
public static final int POWER_COMPONENT_BLUETOOTH = 2;
public static final int POWER_COMPONENT_CAMERA = 3;
@@ -69,13 +71,15 @@
public static final int POWER_COMPONENT_GNSS = 10;
public static final int POWER_COMPONENT_WIFI = 11;
public static final int POWER_COMPONENT_WAKELOCK = 12;
- public static final int POWER_COMPONENT_SCREEN = 13;
+ public static final int POWER_COMPONENT_MEMORY = 13;
+ public static final int POWER_COMPONENT_PHONE = 13;
+ public static final int POWER_COMPONENT_IDLE = 15;
// Power that is re-attributed to other battery consumers. For example, for System Server
// this represents the power attributed to apps requesting system services.
// The value should be negative or zero.
- public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 14;
+ public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS = 16;
- public static final int POWER_COMPONENT_COUNT = 15;
+ public static final int POWER_COMPONENT_COUNT = 17;
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
@@ -87,7 +91,7 @@
* @hide
*/
@IntDef(prefix = {"TIME_COMPONENT_"}, value = {
- TIME_COMPONENT_USAGE,
+ TIME_COMPONENT_SCREEN,
TIME_COMPONENT_CPU,
TIME_COMPONENT_CPU_FOREGROUND,
TIME_COMPONENT_BLUETOOTH,
@@ -98,13 +102,15 @@
TIME_COMPONENT_GNSS,
TIME_COMPONENT_WIFI,
TIME_COMPONENT_WAKELOCK,
- TIME_COMPONENT_SCREEN,
+ TIME_COMPONENT_MEMORY,
+ TIME_COMPONENT_PHONE,
+ TIME_COMPONENT_IDLE,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface TimeComponent {
}
- public static final int TIME_COMPONENT_USAGE = 0;
+ public static final int TIME_COMPONENT_SCREEN = 0;
public static final int TIME_COMPONENT_CPU = 1;
public static final int TIME_COMPONENT_CPU_FOREGROUND = 2;
public static final int TIME_COMPONENT_BLUETOOTH = 3;
@@ -117,9 +123,11 @@
public static final int TIME_COMPONENT_GNSS = 10;
public static final int TIME_COMPONENT_WIFI = 11;
public static final int TIME_COMPONENT_WAKELOCK = 12;
- public static final int TIME_COMPONENT_SCREEN = 13;
+ public static final int TIME_COMPONENT_MEMORY = 13;
+ public static final int TIME_COMPONENT_PHONE = 14;
+ public static final int TIME_COMPONENT_IDLE = 15;
- public static final int TIME_COMPONENT_COUNT = 14;
+ public static final int TIME_COMPONENT_COUNT = 16;
public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
@@ -148,7 +156,7 @@
*/
public static final int POWER_MODEL_MEASURED_ENERGY = 1;
- private final PowerComponents mPowerComponents;
+ protected final PowerComponents mPowerComponents;
protected BatteryConsumer(@NonNull PowerComponents powerComponents) {
mPowerComponents = powerComponents;
@@ -192,6 +200,23 @@
return mPowerComponents.getConsumedPowerForCustomComponent(componentId);
}
+ public int getCustomPowerComponentCount() {
+ return mPowerComponents.getCustomPowerComponentCount();
+ }
+
+ void setCustomPowerComponentNames(String[] customPowerComponentNames) {
+ mPowerComponents.setCustomPowerComponentNames(customPowerComponentNames);
+ }
+
+ /**
+ * Returns the name of the specified power component.
+ *
+ * @param componentId The ID of the custom power component.
+ */
+ public String getCustomPowerComponentName(int componentId) {
+ return mPowerComponents.getCustomPowerComponentName(componentId);
+ }
+
/**
* Returns the amount of time since BatteryStats reset used by the specified component, e.g.
* CPU, WiFi etc.
@@ -222,9 +247,9 @@
protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
final PowerComponents.Builder mPowerComponentsBuilder;
- public BaseBuilder(int customPowerComponentCount, int customTimeComponentCount,
- boolean includePowerModels) {
- mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentCount,
+ public BaseBuilder(@NonNull String[] customPowerComponentNames,
+ int customTimeComponentCount, boolean includePowerModels) {
+ mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentNames,
customTimeComponentCount, includePowerModels);
}
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index f288774..8ea59ce 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -39,9 +39,10 @@
private final double mDischargedPowerUpperBound;
private final long mBatteryTimeRemainingMs;
private final long mChargeTimeRemainingMs;
- private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
- private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
- private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
+ private final String[] mCustomPowerComponentNames;
+ private final List<UidBatteryConsumer> mUidBatteryConsumers;
+ private final List<SystemBatteryConsumer> mSystemBatteryConsumers;
+ private final List<UserBatteryConsumer> mUserBatteryConsumers;
private final Parcel mHistoryBuffer;
private final List<BatteryStats.HistoryTag> mHistoryTagPool;
@@ -54,6 +55,7 @@
mHistoryTagPool = builder.mHistoryTagPool;
mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
+ mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
double totalPower = 0;
@@ -182,12 +184,31 @@
mDischargedPowerUpperBound = source.readDouble();
mBatteryTimeRemainingMs = source.readLong();
mChargeTimeRemainingMs = source.readLong();
- mUidBatteryConsumers = new ArrayList<>();
- source.readParcelableList(mUidBatteryConsumers, getClass().getClassLoader());
- mSystemBatteryConsumers = new ArrayList<>();
- source.readParcelableList(mSystemBatteryConsumers, getClass().getClassLoader());
- mUserBatteryConsumers = new ArrayList<>();
- source.readParcelableList(mUserBatteryConsumers, getClass().getClassLoader());
+ mCustomPowerComponentNames = source.readStringArray();
+ int uidCount = source.readInt();
+ mUidBatteryConsumers = new ArrayList<>(uidCount);
+ for (int i = 0; i < uidCount; i++) {
+ final UidBatteryConsumer consumer =
+ UidBatteryConsumer.CREATOR.createFromParcel(source);
+ consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
+ mUidBatteryConsumers.add(consumer);
+ }
+ int sysCount = source.readInt();
+ mSystemBatteryConsumers = new ArrayList<>(sysCount);
+ for (int i = 0; i < sysCount; i++) {
+ final SystemBatteryConsumer consumer =
+ SystemBatteryConsumer.CREATOR.createFromParcel(source);
+ consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
+ mSystemBatteryConsumers.add(consumer);
+ }
+ int userCount = source.readInt();
+ mUserBatteryConsumers = new ArrayList<>(userCount);
+ for (int i = 0; i < userCount; i++) {
+ final UserBatteryConsumer consumer =
+ UserBatteryConsumer.CREATOR.createFromParcel(source);
+ consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
+ mUserBatteryConsumers.add(consumer);
+ }
if (source.readBoolean()) {
mHistoryBuffer = Parcel.obtain();
mHistoryBuffer.setDataSize(0);
@@ -222,9 +243,19 @@
dest.writeDouble(mDischargedPowerUpperBound);
dest.writeLong(mBatteryTimeRemainingMs);
dest.writeLong(mChargeTimeRemainingMs);
- dest.writeParcelableList(mUidBatteryConsumers, flags);
- dest.writeParcelableList(mSystemBatteryConsumers, flags);
- dest.writeParcelableList(mUserBatteryConsumers, flags);
+ dest.writeStringArray(mCustomPowerComponentNames);
+ dest.writeInt(mUidBatteryConsumers.size());
+ for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
+ mUidBatteryConsumers.get(i).writeToParcel(dest, flags);
+ }
+ dest.writeInt(mSystemBatteryConsumers.size());
+ for (int i = mSystemBatteryConsumers.size() - 1; i >= 0; i--) {
+ mSystemBatteryConsumers.get(i).writeToParcel(dest, flags);
+ }
+ dest.writeInt(mUserBatteryConsumers.size());
+ for (int i = mUserBatteryConsumers.size() - 1; i >= 0; i--) {
+ mUserBatteryConsumers.get(i).writeToParcel(dest, flags);
+ }
if (mHistoryBuffer != null) {
dest.writeBoolean(true);
@@ -259,7 +290,8 @@
* Builder for BatteryUsageStats.
*/
public static final class Builder {
- private final int mCustomPowerComponentCount;
+ @NonNull
+ private final String[] mCustomPowerComponentNames;
private final int mCustomTimeComponentCount;
private final boolean mIncludePowerModels;
private long mStatsStartTimestampMs;
@@ -277,13 +309,13 @@
private Parcel mHistoryBuffer;
private List<BatteryStats.HistoryTag> mHistoryTagPool;
- public Builder(int customPowerComponentCount, int customTimeComponentCount) {
- this(customPowerComponentCount, customTimeComponentCount, false);
+ public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount) {
+ this(customPowerComponentNames, customTimeComponentCount, false);
}
- public Builder(int customPowerComponentCount, int customTimeComponentCount,
+ public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels) {
- mCustomPowerComponentCount = customPowerComponentCount;
+ mCustomPowerComponentNames = customPowerComponentNames;
mCustomTimeComponentCount = customTimeComponentCount;
mIncludePowerModels = includePowerModels;
}
@@ -366,7 +398,7 @@
int uid = batteryStatsUid.getUid();
UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid);
if (builder == null) {
- builder = new UidBatteryConsumer.Builder(mCustomPowerComponentCount,
+ builder = new UidBatteryConsumer.Builder(mCustomPowerComponentNames,
mCustomTimeComponentCount, mIncludePowerModels, batteryStatsUid);
mUidBatteryConsumerBuilders.put(uid, builder);
}
@@ -382,7 +414,7 @@
@SystemBatteryConsumer.DrainType int drainType) {
SystemBatteryConsumer.Builder builder = mSystemBatteryConsumerBuilders.get(drainType);
if (builder == null) {
- builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentCount,
+ builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentNames,
mCustomTimeComponentCount, mIncludePowerModels, drainType);
mSystemBatteryConsumerBuilders.put(drainType, builder);
}
@@ -397,7 +429,7 @@
public UserBatteryConsumer.Builder getOrCreateUserBatteryConsumerBuilder(int userId) {
UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId);
if (builder == null) {
- builder = new UserBatteryConsumer.Builder(mCustomPowerComponentCount,
+ builder = new UserBatteryConsumer.Builder(mCustomPowerComponentNames,
mCustomTimeComponentCount, mIncludePowerModels, userId);
mUserBatteryConsumerBuilders.put(userId, builder);
}
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 238f451..a0a41f4 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -26,7 +26,7 @@
class PowerComponents {
private static final int CUSTOM_POWER_COMPONENT_OFFSET = BatteryConsumer.POWER_COMPONENT_COUNT
- BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
- public static final int CUSTOM_TIME_COMPONENT_OFFSET = BatteryConsumer.TIME_COMPONENT_COUNT
+ private static final int CUSTOM_TIME_COMPONENT_OFFSET = BatteryConsumer.TIME_COMPONENT_COUNT
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID;
private final double mTotalConsumedPowerMah;
@@ -34,9 +34,12 @@
private final long[] mTimeComponentsMs;
private final int mCustomPowerComponentCount;
private final byte[] mPowerModels;
+ // Not written to Parcel and must be explicitly restored during the parent object's unparceling
+ private String[] mCustomPowerComponentNames;
PowerComponents(@NonNull Builder builder) {
- mCustomPowerComponentCount = builder.mCustomPowerComponentCount;
+ mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
+ mCustomPowerComponentCount = mCustomPowerComponentNames.length;
mPowerComponentsMah = builder.mPowerComponentsMah;
mTimeComponentsMs = builder.mTimeComponentsMs;
mTotalConsumedPowerMah = builder.getTotalPower();
@@ -117,6 +120,26 @@
}
}
+ void setCustomPowerComponentNames(String[] customPowerComponentNames) {
+ mCustomPowerComponentNames = customPowerComponentNames;
+ }
+
+ public String getCustomPowerComponentName(int componentId) {
+ if (componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+ && componentId < BatteryConsumer.LAST_CUSTOM_POWER_COMPONENT_ID) {
+ try {
+ return mCustomPowerComponentNames[componentId
+ - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException(
+ "Unsupported custom power component ID: " + componentId);
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported custom power component ID: " + componentId);
+ }
+ }
+
@BatteryConsumer.PowerModel
int getPowerModel(@BatteryConsumer.PowerComponent int component) {
if (mPowerModels == null) {
@@ -164,20 +187,37 @@
}
}
+ public int getCustomPowerComponentCount() {
+ return mCustomPowerComponentCount;
+ }
+
+ /**
+ * Returns the largest usage duration among all time components.
+ */
+ public long getMaxComponentUsageDurationMillis() {
+ long max = 0;
+ for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) {
+ if (mTimeComponentsMs[i] > max) {
+ max = mTimeComponentsMs[i];
+ }
+ }
+ return max;
+ }
+
/**
* Builder for PowerComponents.
*/
static final class Builder {
private final double[] mPowerComponentsMah;
- private final int mCustomPowerComponentCount;
+ private final String[] mCustomPowerComponentNames;
private final long[] mTimeComponentsMs;
private final byte[] mPowerModels;
- Builder(int customPowerComponentCount, int customTimeComponentCount,
+ Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels) {
- mCustomPowerComponentCount = customPowerComponentCount;
+ mCustomPowerComponentNames = customPowerComponentNames;
int powerComponentCount =
- BatteryConsumer.POWER_COMPONENT_COUNT + customPowerComponentCount;
+ BatteryConsumer.POWER_COMPONENT_COUNT + mCustomPowerComponentNames.length;
mPowerComponentsMah = new double[powerComponentCount];
mTimeComponentsMs =
new long[BatteryConsumer.TIME_COMPONENT_COUNT + customTimeComponentCount];
@@ -285,10 +325,10 @@
}
public void addPowerAndDuration(Builder other) {
- for (int i = 0; i < mPowerComponentsMah.length; i++) {
+ for (int i = mPowerComponentsMah.length - 1; i >= 0; i--) {
mPowerComponentsMah[i] += other.mPowerComponentsMah[i];
}
- for (int i = 0; i < mTimeComponentsMs.length; i++) {
+ for (int i = mTimeComponentsMs.length - 1; i >= 0; i--) {
mTimeComponentsMs[i] += other.mTimeComponentsMs[i];
}
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index a42448c..b474d7c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -169,8 +169,9 @@
public @interface ResumeOnRebootRebootErrorCode {}
/**
- * The preparation of resume on reboot succeeds. Don't expose it because a successful reboot
- * should just reboot the device.
+ * The preparation of resume on reboot succeeds.
+ *
+ * <p> Don't expose it because a successful reboot should just reboot the device.
* @hide
*/
public static final int RESUME_ON_REBOOT_REBOOT_ERROR_NONE = 0;
diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java
index e973e4c..1327978 100644
--- a/core/java/android/os/SystemBatteryConsumer.java
+++ b/core/java/android/os/SystemBatteryConsumer.java
@@ -104,6 +104,13 @@
}
/**
+ * Returns the amount of time this consumer was operating.
+ */
+ public long getUsageDurationMillis() {
+ return mPowerComponents.getMaxComponentUsageDurationMillis();
+ }
+
+ /**
* Writes the contents into a Parcel.
*/
@Override
@@ -140,9 +147,9 @@
private double mPowerConsumedByAppsMah;
private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
- Builder(int customPowerComponentCount, int customTimeComponentCount,
+ Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels, @DrainType int drainType) {
- super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
mDrainType = drainType;
}
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 87c263b..92e9603 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -139,9 +139,9 @@
public long mTimeInBackgroundMs;
private boolean mExcludeFromBatteryUsageStats;
- public Builder(int customPowerComponentCount, int customTimeComponentCount,
+ public Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid) {
- super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
mBatteryStatsUid = batteryStatsUid;
mUid = batteryStatsUid.getUid();
}
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
index 7832208..de0a707 100644
--- a/core/java/android/os/UserBatteryConsumer.java
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -77,9 +77,9 @@
private final int mUserId;
private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
- Builder(int customPowerComponentCount, int customTimeComponentCount,
+ Builder(@NonNull String[] customPowerComponentNames, int customTimeComponentCount,
boolean includePowerModels, int userId) {
- super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ super(customPowerComponentNames, customTimeComponentCount, includePowerModels);
mUserId = userId;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 9bfd75e..51f19eb 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -22,10 +22,10 @@
import android.annotation.IntDef;
import android.annotation.LongDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.UserHandleAware;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -129,7 +129,7 @@
public static final int ERROR_STORAGE_FULL = 2;
/**
- * Indicates that the {@link InputStream} passed to {@link #storeCallComposerPictureAsUser}
+ * Indicates that the {@link InputStream} passed to {@link #storeCallComposerPicture}
* was closed.
*
* The caller should retry if this error is encountered, and be sure to not close the stream
@@ -195,9 +195,8 @@
* The caller is responsible for closing the {@link InputStream} after the callback indicating
* success or failure.
*
- * @param context An instance of {@link Context}.
- * @param user The user for whom the picture is stored. If {@code null}, the picture will be
- * stored for all users.
+ * @param context An instance of {@link Context}. The picture will be stored to the user
+ * corresponding to {@link Context#getUser()}.
* @param input An input stream from which the picture to store should be read. The input data
* must be decodeable as either a JPEG, PNG, or GIF image.
* @param executor The {@link Executor} on which to perform the file transfer operation and
@@ -207,12 +206,12 @@
* @hide
*/
@SystemApi
+ @UserHandleAware
@RequiresPermission(allOf = {
Manifest.permission.WRITE_CALL_LOG,
Manifest.permission.INTERACT_ACROSS_USERS
})
- public static void storeCallComposerPictureAsUser(@NonNull Context context,
- @Nullable UserHandle user,
+ public static void storeCallComposerPicture(@NonNull Context context,
@NonNull InputStream input,
@CallbackExecutor @NonNull Executor executor,
@NonNull OutcomeReceiver<Uri, CallComposerLoggingException> callback) {
@@ -246,12 +245,13 @@
byte[] picData = tmpOut.toByteArray();
UserManager userManager = context.getSystemService(UserManager.class);
+ UserHandle user = context.getUser();
// Nasty casework for the shadow calllog begins...
// First see if we're just inserting for one user. If so, insert into the shadow
// based on whether that user is unlocked.
UserHandle realUser = UserHandle.CURRENT.equals(user)
? android.os.Process.myUserHandle() : user;
- if (realUser != null) {
+ if (realUser != UserHandle.ALL) {
Uri baseUri = userManager.isUserUnlocked(realUser) ? CALL_COMPOSER_PICTURE_URI
: SHADOW_CALL_COMPOSER_PICTURE_URI;
Uri pictureInsertionUri = ContentProvider.maybeAddUserId(baseUri,
@@ -625,7 +625,7 @@
}
/**
- * @param pictureUri {@link Uri} returned from {@link #storeCallComposerPictureAsUser}.
+ * @param pictureUri {@link Uri} returned from {@link #storeCallComposerPicture}.
* Associates that stored picture with this call in the log.
*/
public @NonNull AddCallParametersBuilder setPictureUri(@NonNull Uri pictureUri) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9450994..2616a667 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9136,6 +9136,20 @@
"biometric_debug_enabled";
/**
+ * Whether or not biometric is allowed on Keyguard.
+ * @hide
+ */
+ @Readable
+ public static final String BIOMETRIC_KEYGUARD_ENABLED = "biometric_keyguard_enabled";
+
+ /**
+ * Whether or not biometric is allowed for apps (through BiometricPrompt).
+ * @hide
+ */
+ @Readable
+ public static final String BIOMETRIC_APP_ENABLED = "biometric_app_enabled";
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 340fa40..4b18c5a 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -796,13 +796,14 @@
/**
* Notify {@link PhysicalChannelConfig} has changed for a specific subscription.
*
+ * @param slotIndex for which physical channel configs changed.
* @param subId the subId
* @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
*/
- public void notifyPhysicalChannelConfigForSubscriber(
- int subId, List<PhysicalChannelConfig> configs) {
+ public void notifyPhysicalChannelConfigForSubscriber(int slotIndex, int subId,
+ List<PhysicalChannelConfig> configs) {
try {
- sRegistry.notifyPhysicalChannelConfigForSubscriber(subId, configs);
+ sRegistry.notifyPhysicalChannelConfigForSubscriber(slotIndex, subId, configs);
} catch (RemoteException ex) {
// system server crash
}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index bed77e6..95024b3 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -24,9 +24,7 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.content.AttributionSource;
import android.content.Context;
-import android.content.ContextParams;
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.PersistableBundle;
@@ -49,7 +47,7 @@
@SystemApi
@SystemService(Context.UWB_SERVICE)
public final class UwbManager {
- private static final String SERVICE_NAME = "uwb";
+ private static final String SERVICE_NAME = Context.UWB_SERVICE;
private final Context mContext;
private final IUwbAdapter mUwbAdapter;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 0a3963d..be172f7 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -693,71 +693,79 @@
ThreadedRenderer.setFPSDivisor(divisor);
}
+ private void traceMessage(String msg) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, msg);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+
void doFrame(long frameTimeNanos, int frame,
DisplayEventReceiver.VsyncEventData vsyncEventData) {
final long startNanos;
final long frameIntervalNanos = vsyncEventData.frameInterval;
- synchronized (mLock) {
- if (!mFrameScheduled) {
- return; // no work to do
- }
-
- if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
- mDebugPrintNextFrameTimeDelta = false;
- Log.d(TAG, "Frame time delta: "
- + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
- }
-
- long intendedFrameTimeNanos = frameTimeNanos;
- startNanos = System.nanoTime();
- final long jitterNanos = startNanos - frameTimeNanos;
- if (jitterNanos >= frameIntervalNanos) {
- final long skippedFrames = jitterNanos / frameIntervalNanos;
- if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
- Log.i(TAG, "Skipped " + skippedFrames + " frames! "
- + "The application may be doing too much work on its main thread.");
- }
- final long lastFrameOffset = jitterNanos % frameIntervalNanos;
- if (DEBUG_JANK) {
- Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
- + "which is more than the frame interval of "
- + (frameIntervalNanos * 0.000001f) + " ms! "
- + "Skipping " + skippedFrames + " frames and setting frame "
- + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
- }
- frameTimeNanos = startNanos - lastFrameOffset;
- }
-
- if (frameTimeNanos < mLastFrameTimeNanos) {
- if (DEBUG_JANK) {
- Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
- + "previously skipped frame. Waiting for next vsync.");
- }
- scheduleVsyncLocked();
- return;
- }
-
- if (mFPSDivisor > 1) {
- long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
- if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
- scheduleVsyncLocked();
- return;
- }
- }
-
- mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
- vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
- mFrameScheduled = false;
- mLastFrameTimeNanos = frameTimeNanos;
- mLastFrameIntervalNanos = frameIntervalNanos;
- mLastVsyncEventData = vsyncEventData;
- }
-
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"Choreographer#doFrame " + vsyncEventData.id);
}
+ synchronized (mLock) {
+ if (!mFrameScheduled) {
+ traceMessage("Frame not scheduled");
+ return; // no work to do
+ }
+
+ if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
+ mDebugPrintNextFrameTimeDelta = false;
+ Log.d(TAG, "Frame time delta: "
+ + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
+ }
+
+ long intendedFrameTimeNanos = frameTimeNanos;
+ startNanos = System.nanoTime();
+ final long jitterNanos = startNanos - frameTimeNanos;
+ if (jitterNanos >= frameIntervalNanos) {
+ final long skippedFrames = jitterNanos / frameIntervalNanos;
+ if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
+ Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ + "The application may be doing too much work on its main thread.");
+ }
+ final long lastFrameOffset = jitterNanos % frameIntervalNanos;
+ if (DEBUG_JANK) {
+ Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ + "which is more than the frame interval of "
+ + (frameIntervalNanos * 0.000001f) + " ms! "
+ + "Skipping " + skippedFrames + " frames and setting frame "
+ + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
+ }
+ frameTimeNanos = startNanos - lastFrameOffset;
+ }
+
+ if (frameTimeNanos < mLastFrameTimeNanos) {
+ if (DEBUG_JANK) {
+ Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ + "previously skipped frame. Waiting for next vsync.");
+ }
+ traceMessage("Frame time goes backward");
+ scheduleVsyncLocked();
+ return;
+ }
+
+ if (mFPSDivisor > 1) {
+ long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
+ if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
+ traceMessage("Frame skipped due to FPSDivisor");
+ scheduleVsyncLocked();
+ return;
+ }
+ }
+
+ mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
+ vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
+ mFrameScheduled = false;
+ mLastFrameTimeNanos = frameTimeNanos;
+ mLastFrameIntervalNanos = frameIntervalNanos;
+ mLastVsyncEventData = vsyncEventData;
+ }
+
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
@@ -870,7 +878,12 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void scheduleVsyncLocked() {
- mDisplayEventReceiver.scheduleVsync();
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
+ mDisplayEventReceiver.scheduleVsync();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
}
private boolean isRunningOnLooperThreadLocked() {
@@ -967,32 +980,40 @@
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
- // Post the vsync event to the Handler.
- // The idea is to prevent incoming vsync events from completely starving
- // the message queue. If there are no messages in the queue with timestamps
- // earlier than the frame time, then the vsync event will be processed immediately.
- // Otherwise, messages that predate the vsync event will be handled first.
- long now = System.nanoTime();
- if (timestampNanos > now) {
- Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
- + " ms in the future! Check that graphics HAL is generating vsync "
- + "timestamps using the correct timebase.");
- timestampNanos = now;
- }
+ try {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+ "Choreographer#onVsync " + vsyncEventData.id);
+ }
+ // Post the vsync event to the Handler.
+ // The idea is to prevent incoming vsync events from completely starving
+ // the message queue. If there are no messages in the queue with timestamps
+ // earlier than the frame time, then the vsync event will be processed immediately.
+ // Otherwise, messages that predate the vsync event will be handled first.
+ long now = System.nanoTime();
+ if (timestampNanos > now) {
+ Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ + " ms in the future! Check that graphics HAL is generating vsync "
+ + "timestamps using the correct timebase.");
+ timestampNanos = now;
+ }
- if (mHavePendingVsync) {
- Log.w(TAG, "Already have a pending vsync event. There should only be "
- + "one at a time.");
- } else {
- mHavePendingVsync = true;
- }
+ if (mHavePendingVsync) {
+ Log.w(TAG, "Already have a pending vsync event. There should only be "
+ + "one at a time.");
+ } else {
+ mHavePendingVsync = true;
+ }
- mTimestampNanos = timestampNanos;
- mFrame = frame;
- mLastVsyncEventData = vsyncEventData;
- Message msg = Message.obtain(mHandler, this);
- msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
+ mTimestampNanos = timestampNanos;
+ mFrame = frame;
+ mLastVsyncEventData = vsyncEventData;
+ Message msg = Message.obtain(mHandler, this);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
}
@Override
diff --git a/core/java/android/view/ScrollCaptureConnection.java b/core/java/android/view/ScrollCaptureConnection.java
index a6d786e..5fcb011 100644
--- a/core/java/android/view/ScrollCaptureConnection.java
+++ b/core/java/android/view/ScrollCaptureConnection.java
@@ -185,7 +185,8 @@
}
Log.w(TAG, "close(): capture session still active! Ending now.");
// -> UiThread
- mUiThread.execute(() -> mLocal.onScrollCaptureEnd(() -> { /* ignore */ }));
+ final ScrollCaptureCallback callback = mLocal;
+ mUiThread.execute(() -> callback.onScrollCaptureEnd(() -> { /* ignore */ }));
mActive = false;
}
mActive = false;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e450061..21f75d4 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -104,6 +104,7 @@
private static native void nativeApplyTransaction(long transactionObj, boolean sync);
private static native void nativeMergeTransaction(long transactionObj,
long otherTransactionObj);
+ private static native void nativeClearTransaction(long transactionObj);
private static native void nativeSetAnimationTransaction(long transactionObj);
private static native void nativeSetEarlyWakeupStart(long transactionObj);
private static native void nativeSetEarlyWakeupEnd(long transactionObj);
@@ -2602,6 +2603,19 @@
}
/**
+ * Clear the transaction object, without applying it.
+ *
+ * @hide
+ */
+ public void clear() {
+ mResizedSurfaces.clear();
+ mReparentedSurfaces.clear();
+ if (mNativeObject != 0) {
+ nativeClearTransaction(mNativeObject);
+ }
+ }
+
+ /**
* Release the native transaction object, without applying it.
*/
@Override
@@ -3411,10 +3425,14 @@
public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
if (mNativeObject == 0) {
dest.writeInt(0);
- } else {
- dest.writeInt(1);
+ return;
}
+
+ dest.writeInt(1);
nativeWriteTransactionToParcel(mNativeObject, dest);
+ if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+ nativeClearTransaction(mNativeObject);
+ }
}
private void readFromParcel(Parcel in) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2b96a14..7bdf5cf 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -30,6 +30,7 @@
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.HardwareRenderer;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -221,8 +222,35 @@
private int mPendingReportDraws;
- private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
- private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+ /**
+ * Transaction that should be used from the render thread. This transaction is only thread safe
+ * with other calls directly from the render thread.
+ */
+ private final SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
+
+ /**
+ * Transaction that should be used whe
+ * {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All
+ * frame callbacks can use the same transaction since they will be thread safe
+ */
+ private final SurfaceControl.Transaction mFrameCallbackTransaction =
+ new SurfaceControl.Transaction();
+
+ /**
+ * Transaction that should be used for
+ * {@link RenderNode.PositionUpdateListener#positionChanged(long, int, int, int, int)}
+ * The callback is invoked from a thread pool so it's not thread safe with other render thread
+ * transactions. Keep the transactions for position changed callbacks on its own transaction.
+ */
+ private final SurfaceControl.Transaction mPositionChangedTransaction =
+ new SurfaceControl.Transaction();
+
+ /**
+ * A temporary transaction holder that should only be used when applying right away. There
+ * should be no assumption about thread safety for this transaction.
+ */
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
private int mParentSurfaceSequenceId;
private RemoteAccessibilityController mRemoteAccessibilityController =
@@ -432,7 +460,6 @@
* This gets called on a RenderThread worker thread, so members accessed here must
* be protected by a lock.
*/
- final boolean useBLAST = useBLASTSync(viewRoot);
viewRoot.registerRtFrameCallback(frame -> {
try {
synchronized (mSurfaceControlLock) {
@@ -456,8 +483,9 @@
Log.d(TAG, System.identityHashCode(this)
+ " updateSurfaceAlpha RT: set alpha=" + alpha);
}
- mRtTransaction.setAlpha(mSurfaceControl, alpha);
- applyRtTransaction(frame);
+
+ mFrameCallbackTransaction.setAlpha(mSurfaceControl, alpha);
+ applyOrMergeTransaction(mFrameCallbackTransaction, frame);
}
// It's possible that mSurfaceControl is released in the UI thread before
// the transaction completes. If that happens, an exception is thrown, which
@@ -806,7 +834,6 @@
* This gets called on a RenderThread worker thread, so members accessed here must
* be protected by a lock.
*/
- final boolean useBLAST = useBLASTSync(viewRoot);
viewRoot.registerRtFrameCallback(frame -> {
try {
synchronized (mSurfaceControlLock) {
@@ -814,8 +841,8 @@
return;
}
- updateRelativeZ(mRtTransaction);
- applyRtTransaction(frame);
+ updateRelativeZ(mFrameCallbackTransaction);
+ applyOrMergeTransaction(mFrameCallbackTransaction, frame);
}
// It's possible that mSurfaceControl is released in the UI thread before
// the transaction completes. If that happens, an exception is thrown, which
@@ -1380,22 +1407,21 @@
return mRTLastReportedPosition;
}
- private void setParentSpaceRectangle(Rect position, long frameNumber) {
+ private void setParentSpaceRectangle(Rect position, long frameNumber, Transaction t) {
final ViewRootImpl viewRoot = getViewRootImpl();
- applySurfaceTransforms(mSurfaceControl, mRtTransaction, position);
- applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface, frameNumber);
- applyRtTransaction(frameNumber);
+ applySurfaceTransforms(mSurfaceControl, t, position);
+ applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface, frameNumber);
+ applyOrMergeTransaction(t, frameNumber);
}
- private void applyRtTransaction(long frameNumber) {
+ private void applyOrMergeTransaction(Transaction t, long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
boolean useBLAST = viewRoot != null && useBLASTSync(viewRoot);
if (useBLAST) {
// If we are using BLAST, merge the transaction with the viewroot buffer transaction.
- viewRoot.mergeWithNextTransaction(mRtTransaction, frameNumber);
- return;
+ viewRoot.mergeWithNextTransaction(t, frameNumber);
} else {
- mRtTransaction.apply();
+ t.apply();
}
}
@@ -1436,7 +1462,8 @@
left, top, right, bottom));
}
mRTLastReportedPosition.set(left, top, right, bottom);
- setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
+ setParentSpaceRectangle(mRTLastReportedPosition, frameNumber,
+ mPositionChangedTransaction);
// Now overwrite mRTLastReportedPosition with our values
} catch (Exception ex) {
Log.e(TAG, "Exception from repositionChild", ex);
@@ -1448,7 +1475,7 @@
float bottom, float vecX, float vecY, float maxStretch) {
mRtTransaction.setStretchEffect(mSurfaceControl, left, top, right, bottom, vecX, vecY,
maxStretch);
- applyRtTransaction(frameNumber);
+ applyOrMergeTransaction(mRtTransaction, frameNumber);
}
@Override
@@ -1468,14 +1495,12 @@
* need to hold the lock here.
*/
synchronized (mSurfaceControlLock) {
- final ViewRootImpl viewRoot = getViewRootImpl();
-
mRtTransaction.hide(mSurfaceControl);
if (mRtReleaseSurfaces) {
mRtReleaseSurfaces = false;
releaseSurfaces(mRtTransaction);
}
- applyRtTransaction(frameNumber);
+ applyOrMergeTransaction(mRtTransaction, frameNumber);
mRtHandlingPositionUpdates = false;
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8348a5c..76eb882 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -723,6 +723,13 @@
private boolean mNextDrawUseBlastSync = false;
/**
+ * Wait for the blast sync transaction complete callback before drawing and queuing up more
+ * frames. This will prevent out of order buffers submissions when WM has requested to
+ * synchronize with the client.
+ */
+ private boolean mWaitForBlastSyncComplete = false;
+
+ /**
* Keeps track of whether a traverse was triggered while the UI thread was paused. This can
* occur when the client is waiting on another process to submit the transaction that
* contains the buffer. The UI thread needs to wait on the callback before it can submit
@@ -1193,7 +1200,8 @@
Looper.myLooper());
if (mAttachInfo.mThreadedRenderer != null) {
- InputMetricsListener listener = new InputMetricsListener();
+ InputMetricsListener listener =
+ new InputMetricsListener(mInputEventReceiver);
mHardwareRendererObserver = new HardwareRendererObserver(
listener, listener.data, mHandler, true /*waitForPresentTime*/);
mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
@@ -1389,9 +1397,6 @@
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;
- if (mHardwareRendererObserver != null) {
- mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
- }
}
}
}
@@ -2463,7 +2468,7 @@
//
// When the callback is invoked, it will trigger a traversal request if
// mRequestedTraverseWhilePaused is set so there's no need to attempt a retry here.
- if (mNextDrawUseBlastSync) {
+ if (mWaitForBlastSyncComplete) {
if (DEBUG_BLAST) {
Log.w(mTag, "Can't perform draw while waiting for a transaction complete");
}
@@ -3244,10 +3249,6 @@
pendingDrawFinished();
}
}
-
- // We were unable to draw this traversal. Unset this flag since we'll block without
- // ever being able to draw again
- mNextDrawUseBlastSync = false;
}
if (mAttachInfo.mContentCaptureEvents != null) {
@@ -3905,7 +3906,10 @@
mDrawsNeededToReport = 0;
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
} catch (RemoteException e) {
- // Have fun!
+ Log.e(mTag, "Unable to report draw finished", e);
+ mSurfaceChangedTransaction.apply();
+ } finally {
+ mSurfaceChangedTransaction.clear();
}
}
@@ -3990,7 +3994,7 @@
+ " reportNextDraw=" + reportNextDraw
+ " hasBlurUpdates=" + hasBlurUpdates);
}
-
+ mWaitForBlastSyncComplete = nextDrawUseBlastSync;
final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
@@ -4025,6 +4029,7 @@
}
mHandler.postAtFrontOfQueue(() -> {
mNextDrawUseBlastSync = false;
+ mWaitForBlastSyncComplete = false;
if (DEBUG_BLAST) {
Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused
+ " due to a previous skipped traversal.");
@@ -8079,9 +8084,6 @@
ThreadedRenderer hardwareRenderer = mAttachInfo.mThreadedRenderer;
if (hardwareRenderer != null) {
- if (mHardwareRendererObserver != null) {
- hardwareRenderer.removeObserver(mHardwareRendererObserver);
- }
if (mView != null) {
hardwareRenderer.destroyHardwareResources(mView);
}
@@ -8583,12 +8585,18 @@
super.dispose();
}
}
- private WindowInputEventReceiver mInputEventReceiver;
+ WindowInputEventReceiver mInputEventReceiver;
final class InputMetricsListener
implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT];
+ private InputEventReceiver mReceiver;
+
+ InputMetricsListener(InputEventReceiver receiver) {
+ mReceiver = receiver;
+ }
+
@Override
public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID];
@@ -8601,11 +8609,6 @@
// available, we cannot compute end-to-end input latency metrics.
return;
}
- final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
- if (mInputEventReceiver == null) {
- return;
- }
- mInputEventReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
}
}
HardwareRendererObserver mHardwareRendererObserver;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6edd071..616910a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2230,9 +2230,7 @@
public void removeImeSurface(IBinder windowToken) {
synchronized (mH) {
try {
- final Completable.Void value = Completable.createVoid();
- mService.removeImeSurfaceFromWindow(windowToken, ResultCallbacks.of(value));
- Completable.getResult(value);
+ mService.removeImeSurfaceFromWindowAsync(windowToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index db88011..90667cf 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -86,7 +86,8 @@
TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION,
TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION,
TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL,
- TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED, TYPE_LINKS_GENERATED})
+ TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED, TYPE_LINKS_GENERATED,
+ TYPE_READ_CLIPBOARD})
public @interface Type {
// For custom event types, use range 1,000,000+.
}
@@ -135,6 +136,13 @@
public static final int TYPE_ACTIONS_GENERATED = 20;
/** Some text links were generated.*/
public static final int TYPE_LINKS_GENERATED = 21;
+ /**
+ * Read a clipboard.
+ * TODO: Make this public.
+ *
+ * @hide
+ */
+ public static final int TYPE_READ_CLIPBOARD = 22;
@Category
private final int mEventCategory;
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index f4fdf35..c09e8bd 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -302,6 +302,11 @@
}
final LongSparseArray<ViewTranslationResponse> virtualChildResponse =
translatedResult.valueAt(i);
+ if (DEBUG) {
+ // TODO(b/182433547): remove before S release
+ Log.v(TAG, "onVirtualViewTranslationCompleted: receive "
+ + virtualChildResponse + " for AutofillId " + autofillId);
+ }
mActivity.runOnUiThread(() -> {
if (view.getViewTranslationCallback() == null) {
if (DEBUG) {
@@ -341,8 +346,13 @@
}
for (int i = 0; i < resultCount; i++) {
final ViewTranslationResponse response = translatedResult.valueAt(i);
+ if (DEBUG) {
+ // TODO(b/182433547): remove before S release
+ Log.v(TAG, "onTranslationCompleted: response= " + response);
+ }
final AutofillId autofillId = response.getAutofillId();
if (autofillId == null) {
+ Log.w(TAG, "No AutofillId is set in ViewTranslationResponse:" + response);
continue;
}
final View view = mViews.get(autofillId).get();
@@ -394,6 +404,9 @@
final TranslationRequest request = new TranslationRequest.Builder()
.setViewTranslationRequests(requests)
.build();
+ if (DEBUG) {
+ Log.d(TAG, "sendTranslationRequest: request= " + request);
+ }
translator.requestUiTranslate(request, (r) -> r.run(), this::onTranslationCompleted);
}
@@ -508,10 +521,17 @@
private void runForEachView(BiConsumer<View, ViewTranslationCallback> action) {
synchronized (mLock) {
final ArrayMap<AutofillId, WeakReference<View>> views = new ArrayMap<>(mViews);
+ if (views.size() == 0) {
+ Log.w(TAG, "No views can be excuted for runForEachView.");
+ }
mActivity.runOnUiThread(() -> {
final int viewCounts = views.size();
for (int i = 0; i < viewCounts; i++) {
final View view = views.valueAt(i).get();
+ if (DEBUG) {
+ // TODO(b/182433547): remove before S release
+ Log.d(TAG, "runForEachView: view= " + view);
+ }
if (view == null || view.getViewTranslationCallback() == null) {
if (DEBUG) {
Log.d(TAG, "View was gone or ViewTranslationCallback for autofillid "
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 50fca04..95a3dc7 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -104,25 +104,31 @@
/**
* The velocity threshold before the spring animation is considered settled.
- * The idea here is that velocity should be less than 1 pixel per frame (~16ms).
+ * The idea here is that velocity should be less than 0.1 pixel per second.
*/
- private static final double VELOCITY_THRESHOLD = 1.0 / 0.016;
+ private static final double VELOCITY_THRESHOLD = 0.1;
/**
* The value threshold before the spring animation is considered close enough to
- * the destination to be settled. This should be around 1 pixel.
+ * the destination to be settled. This should be around 0.01 pixel.
*/
- private static final double VALUE_THRESHOLD = 1;
+ private static final double VALUE_THRESHOLD = 0.01;
/**
* The natural frequency of the stretch spring.
*/
- private static final double NATURAL_FREQUENCY = 17.55;
+ private static final double NATURAL_FREQUENCY = 24.657;
/**
* The damping ratio of the stretch spring.
*/
- private static final double DAMPING_RATIO = 0.92;
+ private static final double DAMPING_RATIO = 0.98;
+
+ /**
+ * The variation of the velocity for the stretch effect when it meets the bound.
+ * if value is > 1, it will accentuate the absorption of the movement.
+ */
+ private static final float ON_ABSORB_VELOCITY_ADJUSTMENT = 13f;
/** @hide */
@IntDef({TYPE_GLOW, TYPE_STRETCH})
@@ -130,9 +136,9 @@
public @interface EdgeEffectType {
}
- private static final float LINEAR_STRETCH_INTENSITY = 0.06f;
+ private static final float LINEAR_STRETCH_INTENSITY = 0.016f;
- private static final float EXP_STRETCH_INTENSITY = 0.06f;
+ private static final float EXP_STRETCH_INTENSITY = 0.016f;
private static final float SCROLL_DIST_AFFECTED_BY_EXP_STRETCH = 0.33f;
@@ -460,7 +466,7 @@
public void onAbsorb(int velocity) {
if (mEdgeEffectType == TYPE_STRETCH) {
mState = STATE_RECEDE;
- mVelocity = velocity;
+ mVelocity = velocity * ON_ABSORB_VELOCITY_ADJUSTMENT;
mDistance = 0;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
} else {
@@ -782,8 +788,8 @@
* considered at rest or false if it is still animating.
*/
private boolean isAtEquilibrium() {
- double displacement = mDistance * mHeight * LINEAR_STRETCH_INTENSITY; // in pixels
- double velocity = mVelocity * LINEAR_STRETCH_INTENSITY;
+ double displacement = mDistance * mHeight; // in pixels
+ double velocity = mVelocity;
return Math.abs(velocity) < VELOCITY_THRESHOLD
&& Math.abs(displacement) < VALUE_THRESHOLD;
}
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 296d93c..a479b8a 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -17,6 +17,7 @@
package android.widget;
import android.annotation.NonNull;
+import android.os.Build;
import android.text.method.TranslationTransformationMethod;
import android.util.Log;
import android.view.View;
@@ -34,7 +35,10 @@
private static final String TAG = "TextViewTranslationCallback";
- private static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG);
+ // TODO(b/182433547): remove Build.IS_DEBUGGABLE before ship. Enable the logging in debug build
+ // to help the debug during the development phase
+ private static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)
+ || Build.IS_DEBUGGABLE;
private TranslationTransformationMethod mTranslationTransformation;
diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java
index 88584f4..d84f571 100644
--- a/core/java/android/window/WindowContextController.java
+++ b/core/java/android/window/WindowContextController.java
@@ -105,6 +105,7 @@
* a {@link com.android.server.wm.DisplayArea} by
* {@link #attachToDisplayArea(int, int, Bundle)}.
*
+ * @see WindowProviderService#attachToWindowToken(IBinder))
* @see IWindowManager#attachWindowContextToWindowToken(IBinder, IBinder)
*/
public void attachToWindowToken(IBinder windowToken) {
diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java
new file mode 100644
index 0000000..b8619fb
--- /dev/null
+++ b/core/java/android/window/WindowProviderService.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.annotation.UiContext;
+import android.app.ActivityThread;
+import android.app.LoadedApk;
+import android.app.Service;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.Display;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams.WindowType;
+import android.view.WindowManagerImpl;
+
+// TODO(b/159767464): handle #onConfigurationChanged(Configuration)
+/**
+ * A {@link Service} responsible for showing a non-activity window, such as software keyboards or
+ * accessibility overlay windows. This {@link Service} has similar behavior to
+ * {@link WindowContext}, but is represented as {@link Service}.
+ *
+ * @see android.inputmethodservice.InputMethodService
+ * @see android.accessibilityservice.AccessibilityService
+ *
+ * @hide
+ */
+@TestApi
+@UiContext
+public abstract class WindowProviderService extends Service {
+
+ private final WindowTokenClient mWindowToken = new WindowTokenClient();
+ private final WindowContextController mController = new WindowContextController(mWindowToken);
+ private WindowManager mWindowManager;
+
+ /**
+ * Returns the type of this {@link WindowProviderService}.
+ * Each inheriting class must implement this method to provide the type of the window. It is
+ * used similar to {@code type} of {@link Context#createWindowContext(int, Bundle)}
+ *
+ * @see Context#createWindowContext(int, Bundle)
+ *
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("OnNameExpected")
+ // Suppress the lint because it is not a callback and users should provide window type
+ // so we cannot make it final.
+ public abstract @WindowType int getWindowType();
+
+ /**
+ * Returns the option of this {@link WindowProviderService}.
+ * Default is {@code null}. The inheriting class can implement this method to provide the
+ * customization {@code option} of the window. It is used similar to {@code options} of
+ * {@link Context#createWindowContext(int, Bundle)}
+ *
+ * @see Context#createWindowContext(int, Bundle)
+ *
+ * @hide
+ */
+ @TestApi
+ @SuppressLint({"OnNameExpected", "NullableCollection"})
+ // Suppress the lint because it is not a callback and users may override this API to provide
+ // launch option. Also, the return value of this API is null by default.
+ @Nullable
+ public Bundle getWindowContextOptions() {
+ return null;
+ }
+
+ /**
+ * Attaches this WindowProviderService to the {@code windowToken}.
+ *
+ * @hide
+ */
+ @TestApi
+ public final void attachToWindowToken(@NonNull IBinder windowToken) {
+ mController.attachToWindowToken(windowToken);
+ }
+
+ /** @hide */
+ @Override
+ public final Context createServiceBaseContext(ActivityThread mainThread,
+ LoadedApk packageInfo) {
+ final Context context = super.createServiceBaseContext(mainThread, packageInfo);
+ // Always associate with the default display at initialization.
+ final Display defaultDisplay = context.getSystemService(DisplayManager.class)
+ .getDisplay(DEFAULT_DISPLAY);
+ return context.createTokenContext(mWindowToken, defaultDisplay);
+ }
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mWindowToken.attachContext(this);
+ mController.attachToDisplayArea(getWindowType(), getDisplayId(), getWindowContextOptions());
+ mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this);
+ }
+
+ @SuppressLint("OnNameExpected")
+ @Override
+ // Suppress the lint because ths is overridden from Context.
+ public @Nullable Object getSystemService(@NonNull String name) {
+ if (WINDOW_SERVICE.equals(name)) {
+ return mWindowManager;
+ }
+ return super.getSystemService(name);
+ }
+
+ @CallSuper
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mController.detachIfNeeded();
+ }
+}
diff --git a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
index 03da9bc..0047f43 100644
--- a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
+++ b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.DialogInterface;
@@ -53,6 +55,8 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
Intent intent = getIntent();
mUserName = intent.getStringExtra(UserManager.EXTRA_USER_NAME);
mAccountName = intent.getStringExtra(UserManager.EXTRA_USER_ACCOUNT_NAME);
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 86f29a8..84354d9 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -27,8 +27,12 @@
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.KeyguardManager;
+import android.app.usage.UsageStatsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -64,9 +68,26 @@
private int mNeutralButtonAction;
private int mUserId;
private PackageManager mPm;
+ private UsageStatsManager mUsm;
private Resources mSuspendingAppResources;
private SuspendDialogInfo mSuppliedDialogInfo;
private Bundle mOptions;
+ private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) {
+ final String[] unsuspended = intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) {
+ if (!isFinishing()) {
+ Slog.w(TAG, "Package " + mSuspendedPackage
+ + " got unsuspended while the dialog was visible. Finishing.");
+ SuspendedAppActivity.this.finish();
+ }
+ }
+ }
+ }
+ };
private CharSequence getAppLabel(String packageName) {
try {
@@ -183,6 +204,7 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPm = getPackageManager();
+ mUsm = getSystemService(UsageStatsManager.class);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
final Intent intent = getIntent();
@@ -222,6 +244,16 @@
requestDismissKeyguardIfNeeded(ap.mMessage);
setupAlert();
+
+ final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null,
+ null);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mUnsuspendReceiver);
}
private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {
@@ -292,6 +324,7 @@
}
break;
}
+ mUsm.reportUserInteraction(mSuspendingPackage, mUserId);
finish();
}
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index 2f49582..aa416c5 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -52,8 +52,8 @@
measuredEnergyUC, mPowerEstimator, durationMs);
builder.getOrCreateSystemBatteryConsumerBuilder(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah, powerModel)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs);
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah, powerModel)
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs);
}
/**
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ac72d29..cb1900f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -40,6 +40,7 @@
import android.net.NetworkStats;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Binder;
@@ -160,7 +161,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 196;
+ static final int VERSION = 197;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -6947,6 +6948,22 @@
return mGlobalMeasuredEnergyStats.getAccumulatedCustomBucketCharges();
}
+ /**
+ * Returns the names of custom power components.
+ */
+ public @NonNull String[] getCustomPowerComponentNames() {
+ if (mGlobalMeasuredEnergyStats == null) {
+ return new String[0];
+ }
+ final String[] names = mGlobalMeasuredEnergyStats.getCustomBucketNames();
+ for (int i = 0; i < names.length; i++) {
+ if (TextUtils.isEmpty(names[i])) {
+ names[i] = "CUSTOM_" + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + i;
+ }
+ }
+ return names;
+ }
+
@Override public long getStartClockTime() {
final long currentTimeMs = System.currentTimeMillis();
if ((currentTimeMs > MILLISECONDS_IN_YEAR
@@ -14379,17 +14396,18 @@
mConstants.startObserving(context.getContentResolver());
registerUsbStateReceiver(context);
}
+
/**
* Initialize the measured charge stats data structures.
*
* @param supportedStandardBuckets boolean array indicating which {@link StandardPowerBucket}s
- * are currently supported.
- * If null, none are supported (regardless of numCustomBuckets).
- * @param numCustomBuckets number of custom (OTHER) EnergyConsumers on this device
+ * are currently supported. If null, none are supported
+ * (regardless of customBucketNames).
+ * @param customBucketNames names of custom (OTHER) EnergyConsumers on this device
*/
@GuardedBy("this")
public void initMeasuredEnergyStatsLocked(@Nullable boolean[] supportedStandardBuckets,
- int numCustomBuckets) {
+ String[] customBucketNames) {
boolean supportedBucketMismatch = false;
mScreenStateAtLastEnergyMeasurement = mScreenState;
@@ -14401,10 +14419,10 @@
} else {
if (mGlobalMeasuredEnergyStats == null) {
mGlobalMeasuredEnergyStats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
} else {
supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
- supportedStandardBuckets, numCustomBuckets);
+ supportedStandardBuckets, customBucketNames);
}
if (supportedStandardBuckets[MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH]) {
@@ -14423,7 +14441,7 @@
if (supportedBucketMismatch) {
mGlobalMeasuredEnergyStats = supportedStandardBuckets == null
- ? null : new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ ? null : new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
// Supported power buckets changed since last boot.
// Existing data is no longer reliable.
resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime());
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 49c564b..c3986c2 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -123,11 +123,7 @@
final long realtimeUs = mStats.mClocks.elapsedRealtime() * 1000;
final long uptimeUs = mStats.mClocks.uptimeMillis() * 1000;
- final long[] customMeasuredChargesUC =
- mStats.getCustomConsumerMeasuredBatteryConsumptionUC();
- final int customPowerComponentCount = customMeasuredChargesUC != null
- ? customMeasuredChargesUC.length
- : 0;
+ final String[] customPowerComponentNames = mStats.getCustomPowerComponentNames();
// TODO(b/174186358): read extra time component number from configuration
final int customTimeComponentCount = 0;
@@ -136,7 +132,7 @@
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
- customPowerComponentCount, customTimeComponentCount, includePowerModels);
+ customPowerComponentNames, customTimeComponentCount, includePowerModels);
batteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime());
SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
diff --git a/core/java/com/android/internal/os/BinderLatencyObserver.java b/core/java/com/android/internal/os/BinderLatencyObserver.java
index 59cc66d..4ca59be 100644
--- a/core/java/com/android/internal/os/BinderLatencyObserver.java
+++ b/core/java/com/android/internal/os/BinderLatencyObserver.java
@@ -16,22 +16,37 @@
package com.android.internal.os;
+import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
+
import android.annotation.Nullable;
import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BinderInternal.CallSession;
+import com.android.internal.os.BinderLatencyProto.ApiStats;
+import com.android.internal.os.BinderLatencyProto.Dims;
+import com.android.internal.os.BinderLatencyProto.RepeatedApiStats;
+import com.android.internal.util.FrameworkStatsLog;
import java.util.Random;
/** Collects statistics about Binder call latency per calling API and method. */
public class BinderLatencyObserver {
private static final String TAG = "BinderLatencyObserver";
+ private static final int MAX_ATOM_SIZE_BYTES = 4064;
+ // Be conservative and leave 1K space for the last histogram so we don't go over the size limit.
+ private static final int LAST_HISTOGRAM_BUFFER_SIZE_BYTES = 1000;
+
+ // Latency observer parameters.
public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 10;
+ public static final int STATSD_PUSH_INTERVAL_MINUTES_DEFAULT = 360;
// Histogram buckets parameters.
public static final int BUCKET_COUNT_DEFAULT = 100;
@@ -50,20 +65,124 @@
private int mFirstBucketSize = FIRST_BUCKET_SIZE_DEFAULT;
private float mBucketScaleFactor = BUCKET_SCALE_FACTOR_DEFAULT;
+ private int mStatsdPushIntervalMinutes = STATSD_PUSH_INTERVAL_MINUTES_DEFAULT;
+
private final Random mRandom;
private BinderLatencyBuckets mLatencyBuckets;
+ private final Handler mLatencyObserverHandler;
+
+ private Runnable mLatencyObserverRunnable = new Runnable() {
+ @Override
+ public void run() {
+ // Schedule the next push.
+ noteLatencyDelayed();
+
+ ArrayMap<LatencyDims, int[]> histogramMap;
+ synchronized (mLock) {
+ // Copy the histograms map so we don't use the lock for longer than needed.
+ histogramMap = new ArrayMap<>(mLatencyHistograms);
+ mLatencyHistograms.clear();
+ }
+
+ BinderTransactionNameResolver resolver = new BinderTransactionNameResolver();
+ ProtoOutputStream proto = new ProtoOutputStream();
+ int histogramsWritten = 0;
+
+ for (LatencyDims dims : histogramMap.keySet()) {
+ // Start a new atom if the next histogram risks going over the atom size limit.
+ if (proto.getRawSize() + LAST_HISTOGRAM_BUFFER_SIZE_BYTES > getMaxAtomSizeBytes()) {
+ if (histogramsWritten > 0) {
+ writeAtomToStatsd(proto);
+ }
+ proto = new ProtoOutputStream();
+ histogramsWritten = 0;
+ }
+
+ String transactionName = resolver.getMethodName(
+ dims.getBinderClass(), dims.getTransactionCode());
+ fillApiStatsProto(proto, dims, transactionName, histogramMap.get(dims));
+ histogramsWritten++;
+ }
+ // Push the final atom.
+ if (histogramsWritten > 0) {
+ writeAtomToStatsd(proto);
+ }
+ }
+ };
+
+ private void fillApiStatsProto(
+ ProtoOutputStream proto, LatencyDims dims, String transactionName, int[] histogram) {
+ // Find the part of the histogram to write.
+ int firstNonEmptyBucket = 0;
+ for (int i = 0; i < mBucketCount; i++) {
+ if (histogram[i] != 0) {
+ firstNonEmptyBucket = i;
+ break;
+ }
+ }
+ int lastNonEmptyBucket = mBucketCount - 1;
+ for (int i = mBucketCount - 1; i >= 0; i--) {
+ if (histogram[i] != 0) {
+ lastNonEmptyBucket = i;
+ break;
+ }
+ }
+
+ // Start a new ApiStats proto.
+ long apiStatsToken = proto.start(RepeatedApiStats.API_STATS);
+
+ // Write the dims.
+ long dimsToken = proto.start(ApiStats.DIMS);
+ proto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ proto.write(Dims.SERVICE_CLASS_NAME, dims.getBinderClass().getName());
+ proto.write(Dims.SERVICE_METHOD_NAME, transactionName);
+ proto.end(dimsToken);
+
+ // Write the histogram.
+ proto.write(ApiStats.FIRST_BUCKET_INDEX, firstNonEmptyBucket);
+ for (int i = firstNonEmptyBucket; i <= lastNonEmptyBucket; i++) {
+ proto.write(ApiStats.BUCKETS, histogram[i]);
+ }
+
+ proto.end(apiStatsToken);
+ }
+
+ protected int getMaxAtomSizeBytes() {
+ return MAX_ATOM_SIZE_BYTES;
+ }
+
+ protected void writeAtomToStatsd(ProtoOutputStream atom) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BINDER_LATENCY_REPORTED,
+ atom.getBytes(),
+ mPeriodicSamplingInterval,
+ 1);
+ }
+
+ private void noteLatencyDelayed() {
+ mLatencyObserverHandler.removeCallbacks(mLatencyObserverRunnable);
+ mLatencyObserverHandler.postDelayed(mLatencyObserverRunnable,
+ mStatsdPushIntervalMinutes * 60 * 1000);
+ }
+
/** Injector for {@link BinderLatencyObserver}. */
public static class Injector {
public Random getRandomGenerator() {
return new Random();
}
+
+ public Handler getHandler() {
+ return new Handler(Looper.getMainLooper());
+ }
}
public BinderLatencyObserver(Injector injector) {
mRandom = injector.getRandomGenerator();
+ mLatencyObserverHandler = injector.getHandler();
mLatencyBuckets = new BinderLatencyBuckets(
mBucketCount, mFirstBucketSize, mBucketScaleFactor);
+ noteLatencyDelayed();
}
/** Should be called when a Binder call completes, will store latency data. */
@@ -73,7 +192,8 @@
}
LatencyDims dims = new LatencyDims(s.binderClass, s.transactionCode);
- long callDuration = getElapsedRealtimeMicro() - s.timeStarted;
+ long elapsedTimeMicro = getElapsedRealtimeMicro();
+ long callDuration = elapsedTimeMicro - s.timeStarted;
// Find the bucket this sample should go to.
int bucketIdx = mLatencyBuckets.sampleToBucket(
@@ -117,6 +237,22 @@
}
}
+ /** Updates the statsd push interval. */
+ public void setPushInterval(int pushIntervalMinutes) {
+ if (pushIntervalMinutes <= 0) {
+ Slog.w(TAG, "Ignored invalid push interval (value must be positive): "
+ + pushIntervalMinutes);
+ return;
+ }
+
+ synchronized (mLock) {
+ if (pushIntervalMinutes != mStatsdPushIntervalMinutes) {
+ mStatsdPushIntervalMinutes = pushIntervalMinutes;
+ reset();
+ }
+ }
+ }
+
/** Updates the histogram buckets parameters. */
public void setHistogramBucketsParams(
int bucketCount, int firstBucketSize, float bucketScaleFactor) {
@@ -138,6 +274,7 @@
synchronized (mLock) {
mLatencyHistograms.clear();
}
+ noteLatencyDelayed();
}
/** Container for binder latency information. */
@@ -187,4 +324,9 @@
public ArrayMap<LatencyDims, int[]> getLatencyHistograms() {
return mLatencyHistograms;
}
+
+ @VisibleForTesting
+ public Runnable getStatsdPushRunnable() {
+ return mLatencyObserverRunnable;
+ }
}
diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java
index 4a4991b..5cb54bd 100644
--- a/core/java/com/android/internal/os/IdlePowerCalculator.java
+++ b/core/java/com/android/internal/os/IdlePowerCalculator.java
@@ -54,8 +54,8 @@
BatteryStats.STATS_SINCE_CHARGED);
if (mPowerMah != 0) {
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_IDLE)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, mPowerMah)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, mDurationMs);
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE, mPowerMah)
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE, mDurationMs);
}
}
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
index 21dcce9..9ec40c6 100644
--- a/core/java/com/android/internal/os/MemoryPowerCalculator.java
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -32,8 +32,8 @@
final double powerMah = calculatePower(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_MEMORY)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah);
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY, durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY, powerMah);
}
@Override
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index 362ca07..6f279d99 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -45,8 +45,8 @@
final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
if (phoneOnPower != 0) {
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_PHONE)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, phoneOnPower)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, phoneOnTimeMs);
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_PHONE, phoneOnTimeMs);
}
}
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 0267def..0743c89 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -96,9 +96,9 @@
}
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN)
- .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE,
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN,
totalPowerAndDuration.durationMs)
- .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE,
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
Math.max(totalPowerAndDuration.powerMah, totalAppPower), powerModel)
.setPowerConsumedByApps(totalAppPower);
}
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 00a0627..3153071 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -23,6 +23,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
+import android.text.TextUtils;
import android.util.DebugUtils;
import android.util.Slog;
import android.view.Display;
@@ -88,13 +89,15 @@
*/
private final long[] mAccumulatedChargeMicroCoulomb;
+ private final String[] mCustomBucketNames;
+
/**
* Creates a MeasuredEnergyStats set to support the provided power buckets.
* supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_POWER_BUCKETS}.
* numCustomBuckets >= 0 is the number of (non-standard) custom power buckets on the device.
*/
- public MeasuredEnergyStats(boolean[] supportedStandardBuckets, int numCustomBuckets) {
- final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets;
+ public MeasuredEnergyStats(boolean[] supportedStandardBuckets, String[] customBucketNames) {
+ final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length;
mAccumulatedChargeMicroCoulomb = new long[numTotalBuckets];
// Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE.
// All custom buckets are, by definition, supported, so their values stay at 0.
@@ -103,6 +106,7 @@
mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE;
}
}
+ mCustomBucketNames = customBucketNames;
}
/**
@@ -119,6 +123,7 @@
mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE;
}
}
+ mCustomBucketNames = template.getCustomBucketNames();
}
/**
@@ -135,6 +140,7 @@
*/
private MeasuredEnergyStats(int numIndices) {
mAccumulatedChargeMicroCoulomb = new long[numIndices];
+ mCustomBucketNames = new String[0];
}
/** Construct from parcel. */
@@ -142,12 +148,14 @@
final int size = in.readInt();
mAccumulatedChargeMicroCoulomb = new long[size];
in.readLongArray(mAccumulatedChargeMicroCoulomb);
+ mCustomBucketNames = in.readStringArray();
}
/** Write to parcel */
public void writeToParcel(Parcel out) {
out.writeInt(mAccumulatedChargeMicroCoulomb.length);
out.writeLongArray(mAccumulatedChargeMicroCoulomb);
+ out.writeStringArray(mCustomBucketNames);
}
/**
@@ -294,7 +302,7 @@
final int numCustomBuckets = arraySize - NUMBER_STANDARD_POWER_BUCKETS;
final MeasuredEnergyStats stats = new MeasuredEnergyStats(
- new boolean[NUMBER_STANDARD_POWER_BUCKETS], numCustomBuckets);
+ new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[numCustomBuckets]);
stats.readSummaryFromParcel(in, true);
return stats;
}
@@ -406,12 +414,12 @@
/** Check if the supported power buckets are precisely those given. */
public boolean isSupportEqualTo(
- @NonNull boolean[] queriedStandardBuckets, int numCustomBuckets) {
+ @NonNull boolean[] queriedStandardBuckets, String[] customBucketNames) {
final int numBuckets = getNumberOfIndices();
// TODO(b/178504428): Detect whether custom buckets have changed qualitatively, not just
// quantitatively, and treat as mismatch if so.
- if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets) {
+ if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length) {
return false;
}
for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) {
@@ -422,6 +430,10 @@
return true;
}
+ public String[] getCustomBucketNames() {
+ return mCustomBucketNames;
+ }
+
/** Dump debug data. */
public void dump(PrintWriter pw) {
pw.print(" ");
@@ -443,11 +455,16 @@
* If the index is a standard bucket, returns its name; otherwise returns its prefixed custom
* bucket number.
*/
- private static String getBucketName(int index) {
+ private String getBucketName(int index) {
if (isValidStandardBucket(index)) {
return DebugUtils.valueToString(MeasuredEnergyStats.class, "POWER_BUCKET_", index);
}
- return "CUSTOM_" + indexToCustomBucket(index);
+ final int customBucket = indexToCustomBucket(index);
+ StringBuilder name = new StringBuilder().append("CUSTOM_").append(customBucket);
+ if (mCustomBucketNames != null && !TextUtils.isEmpty(mCustomBucketNames[customBucket])) {
+ name.append('(').append(mCustomBucketNames[customBucket]).append(')');
+ }
+ return name.toString();
}
/** Get the number of custom power buckets on this device. */
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index e438d39..a0a0f32 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -92,7 +92,7 @@
void notifyRegistrationFailed(int slotIndex, int subId, in CellIdentity cellIdentity,
String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
void notifyBarringInfoChanged(int slotIndex, int subId, in BarringInfo barringInfo);
- void notifyPhysicalChannelConfigForSubscriber(in int subId,
+ void notifyPhysicalChannelConfigForSubscriber(in int phoneId, in int subId,
in List<PhysicalChannelConfig> configs);
void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason);
void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType);
diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java
index 4613dad..d5c0f60 100644
--- a/core/java/com/android/internal/util/State.java
+++ b/core/java/com/android/internal/util/State.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Message;
@@ -25,6 +26,7 @@
*
* The class for implementing states in a StateMachine
*/
+@SuppressLint("AndroidFrameworkRequiresPermission")
public class State implements IState {
/**
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 50bbfc5..fd13c26b 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -89,8 +89,7 @@
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
oneway void removeImeSurface(in IVoidResultCallback resultCallback);
/** Remove the IME surface. Requires passing the currently focused window. */
- oneway void removeImeSurfaceFromWindow(in IBinder windowToken,
- in IVoidResultCallback resultCallback);
+ oneway void removeImeSurfaceFromWindowAsync(in IBinder windowToken);
oneway void startProtoDump(in byte[] protoDump, int source, String where,
in IVoidResultCallback resultCallback);
oneway void isImeTraceEnabled(in IBooleanResultCallback resultCallback);
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
index 9829d0b..356cd6b 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewHelper.java
@@ -19,8 +19,14 @@
import android.annotation.NonNull;
import android.graphics.Rect;
import android.view.View;
+import android.view.ViewGroup;
-interface ScrollCaptureViewHelper<V extends View> {
+/**
+ * Provides view-specific handling to ScrollCaptureViewSupport.
+ *
+ * @param <V> the View subclass
+ */
+public interface ScrollCaptureViewHelper<V extends View> {
int UP = -1;
int DOWN = 1;
@@ -73,9 +79,12 @@
* @param view the view being captured
*/
@NonNull default Rect onComputeScrollBounds(@NonNull V view) {
- return new Rect(view.getPaddingLeft(), view.getPaddingTop(),
- view.getWidth() - view.getPaddingRight(),
- view.getHeight() - view.getPaddingBottom());
+ Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
+ if (view instanceof ViewGroup && ((ViewGroup) view).getClipToPadding()) {
+ bounds.inset(view.getPaddingLeft(), view.getPaddingTop(),
+ view.getPaddingRight(), view.getPaddingBottom());
+ }
+ return bounds;
}
/**
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index a41511b..8aa2d57 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -17,6 +17,7 @@
package com.android.internal.view;
import android.annotation.UiThread;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.HardwareRenderer;
@@ -26,6 +27,7 @@
import android.graphics.RectF;
import android.graphics.RenderNode;
import android.os.CancellationSignal;
+import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display.ColorMode;
@@ -53,11 +55,14 @@
private static final String TAG = "ScrollCaptureViewSupport";
- private static final boolean WAIT_FOR_ANIMATION = true;
+ private static final String SETTING_CAPTURE_DELAY = "screenshot.scroll_capture_delay";
+ private static final long SETTING_CAPTURE_DELAY_DEFAULT = 60L; // millis
private final WeakReference<V> mWeakView;
private final ScrollCaptureViewHelper<V> mViewHelper;
private final ViewRenderer mRenderer;
+ private final long mPostScrollDelayMillis;
+
private boolean mStarted;
private boolean mEnded;
@@ -66,6 +71,10 @@
mRenderer = new ViewRenderer();
// TODO(b/177649144): provide access to color space from android.media.Image
mViewHelper = viewHelper;
+ Context context = containingView.getContext();
+ ContentResolver contentResolver = context.getContentResolver();
+ mPostScrollDelayMillis = Settings.Global.getLong(contentResolver,
+ SETTING_CAPTURE_DELAY, SETTING_CAPTURE_DELAY_DEFAULT);
}
/** Based on ViewRootImpl#updateColorModeIfNeeded */
@@ -120,37 +129,41 @@
public final void onScrollCaptureImageRequest(ScrollCaptureSession session,
CancellationSignal signal, Rect requestRect, Consumer<Rect> onComplete) {
if (signal.isCanceled()) {
+ Log.w(TAG, "onScrollCaptureImageRequest: cancelled!");
return;
}
+
V view = mWeakView.get();
if (view == null || !view.isVisibleToUser()) {
// Signal to the controller that we have a problem and can't continue.
onComplete.accept(new Rect());
return;
}
+
// Ask the view to scroll as needed to bring this area into view.
ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(),
requestRect);
+
if (scrollResult.availableArea.isEmpty()) {
onComplete.accept(scrollResult.availableArea);
return;
}
- view.invalidate(); // don't wait for vsync
// For image capture, shift back by scrollDelta to arrive at the location within the view
// where the requested content will be drawn
Rect viewCaptureArea = new Rect(scrollResult.availableArea);
viewCaptureArea.offset(0, -scrollResult.scrollDelta);
- if (WAIT_FOR_ANIMATION) {
- view.postOnAnimation(() -> {
+ Runnable captureAction = () -> {
+ if (signal.isCanceled()) {
+ Log.w(TAG, "onScrollCaptureImageRequest: cancelled! skipping render.");
+ } else {
mRenderer.renderView(view, viewCaptureArea);
onComplete.accept(new Rect(scrollResult.availableArea));
- });
- } else {
- mRenderer.renderView(view, viewCaptureArea);
- onComplete.accept(new Rect(scrollResult.availableArea));
- }
+ }
+ };
+
+ view.postOnAnimationDelayed(captureAction, mPostScrollDelayMillis);
}
@Override
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 8ecc809..bab4e93b 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -64,6 +64,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
@@ -530,13 +531,7 @@
mConversationText.setText(conversationText);
// Update if the groups can hide the sender if they are first (applies to 1:1 conversations)
// This needs to happen after all of the above o update all of the groups
- for (int i = mGroups.size() - 1; i >= 0; i--) {
- MessagingGroup messagingGroup = mGroups.get(i);
- CharSequence messageSender = messagingGroup.getSenderName();
- boolean canHide = mIsOneToOne
- && TextUtils.equals(conversationText, messageSender);
- messagingGroup.setCanHideSenderIfFirst(canHide);
- }
+ mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText);
updateAppName();
updateIconPositionAndSize();
updateImageMessages();
@@ -779,35 +774,7 @@
private void updateTitleAndNamesDisplay() {
// Map of unique names to their prefix
- ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
- // Map of single-character string prefix to the only name which uses it, or null if multiple
- ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>();
- for (int i = 0; i < mGroups.size(); i++) {
- MessagingGroup group = mGroups.get(i);
- CharSequence senderName = group.getSenderName();
- if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
- continue;
- }
- if (!uniqueNames.containsKey(senderName)) {
- String charPrefix = mPeopleHelper.findNamePrefix(senderName, null);
- if (charPrefix == null) {
- continue;
- }
- if (uniqueCharacters.containsKey(charPrefix)) {
- // this character was already used, lets make it more unique. We first need to
- // resolve the existing character if it exists
- CharSequence existingName = uniqueCharacters.get(charPrefix);
- if (existingName != null) {
- uniqueNames.put(existingName, mPeopleHelper.findNameSplit(existingName));
- uniqueCharacters.put(charPrefix, null);
- }
- uniqueNames.put(senderName, mPeopleHelper.findNameSplit(senderName));
- } else {
- uniqueNames.put(senderName, charPrefix);
- uniqueCharacters.put(charPrefix, senderName);
- }
- }
- }
+ Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups);
// Now that we have the correct symbols, let's look what we have cached
ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a0e50be..db4e673 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -933,19 +933,6 @@
}
/**
- * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
- * Not the most secure, but it is at least a second level of protection. First level is that
- * the file is in a location only readable by the system process.
- *
- * @param password the gesture pattern.
- *
- * @return the hash of the pattern in a byte array.
- */
- public String legacyPasswordToHash(byte[] password, int userId) {
- return LockscreenCredential.legacyPasswordToHash(password, getSalt(userId).getBytes());
- }
-
- /**
* Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
* {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
* {@link #CREDENTIAL_TYPE_PASSWORD}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index f5df3ab..940979d 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -16,15 +16,41 @@
package com.android.internal.widget;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.admin.PasswordMetrics;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* LockSettingsService local system service interface.
*
* @hide Only for use within the system server.
*/
public abstract class LockSettingsInternal {
+ /** ErrorCode for armRebootEscrow failures. **/
+ @IntDef(prefix = {"ARM_REBOOT_ERROR_"}, value = {
+ ARM_REBOOT_ERROR_NONE,
+ ARM_REBOOT_ERROR_UNSPECIFIED,
+ ARM_REBOOT_ERROR_ESCROW_NOT_READY,
+ ARM_REBOOT_ERROR_NO_PROVIDER,
+ ARM_REBOOT_ERROR_PROVIDER_MISMATCH,
+ ARM_REBOOT_ERROR_NO_ESCROW_KEY,
+ ARM_REBOOT_ERROR_KEYSTORE_FAILURE,
+ ARM_REBOOT_ERROR_STORE_ESCROW_KEY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ArmRebootEscrowErrorCode {}
+
+ public static final int ARM_REBOOT_ERROR_NONE = 0;
+ public static final int ARM_REBOOT_ERROR_UNSPECIFIED = 1;
+ public static final int ARM_REBOOT_ERROR_ESCROW_NOT_READY = 2;
+ public static final int ARM_REBOOT_ERROR_NO_PROVIDER = 3;
+ public static final int ARM_REBOOT_ERROR_PROVIDER_MISMATCH = 4;
+ public static final int ARM_REBOOT_ERROR_NO_ESCROW_KEY = 5;
+ public static final int ARM_REBOOT_ERROR_KEYSTORE_FAILURE = 6;
+ public static final int ARM_REBOOT_ERROR_STORE_ESCROW_KEY = 7;
+ // TODO(b/183140900) split store escrow key errors into detailed ones.
/**
* Create an escrow token for the current user, which can later be used to unlock FBE
@@ -104,9 +130,9 @@
* Should be called immediately before rebooting for an update. This depends on {@link
* #prepareRebootEscrow()} having been called and the escrow completing.
*
- * @return true if the arming worked
+ * @return ARM_ERROR_NONE if the arming worked
*/
- public abstract boolean armRebootEscrow();
+ public abstract @ArmRebootEscrowErrorCode int armRebootEscrow();
/**
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index f312d1d..f30b844 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -24,6 +24,7 @@
import android.app.Person;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
@@ -109,7 +110,10 @@
private boolean mIsInConversation = true;
private ViewGroup mMessagingIconContainer;
private int mConversationContentStart;
- private int mNonConversationMarginEnd;
+ private int mNonConversationContentStart;
+ private int mNonConversationPaddingStart;
+ private int mConversationAvatarSize;
+ private int mNonConversationAvatarSize;
private int mNotificationTextMarginTop;
public MessagingGroup(@NonNull Context context) {
@@ -141,16 +145,21 @@
mMessagingIconContainer = findViewById(R.id.message_icon_container);
mContentContainer = findViewById(R.id.messaging_group_content_container);
mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container);
- DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+ Resources res = getResources();
+ DisplayMetrics displayMetrics = res.getDisplayMetrics();
mDisplaySize.x = displayMetrics.widthPixels;
mDisplaySize.y = displayMetrics.heightPixels;
- mSenderTextPaddingSingleLine = getResources().getDimensionPixelSize(
+ mSenderTextPaddingSingleLine = res.getDimensionPixelSize(
R.dimen.messaging_group_singleline_sender_padding_end);
- mConversationContentStart = getResources().getDimensionPixelSize(
- R.dimen.conversation_content_start);
- mNonConversationMarginEnd = getResources().getDimensionPixelSize(
- R.dimen.messaging_layout_margin_end);
- mNotificationTextMarginTop = getResources().getDimensionPixelSize(
+ mConversationContentStart = res.getDimensionPixelSize(R.dimen.conversation_content_start);
+ mNonConversationContentStart = res.getDimensionPixelSize(
+ R.dimen.notification_content_margin_start);
+ mNonConversationPaddingStart = res.getDimensionPixelSize(
+ R.dimen.messaging_layout_icon_padding_start);
+ mConversationAvatarSize = res.getDimensionPixelSize(R.dimen.messaging_avatar_size);
+ mNonConversationAvatarSize = res.getDimensionPixelSize(
+ R.dimen.notification_icon_circle_size);
+ mNotificationTextMarginTop = res.getDimensionPixelSize(
R.dimen.notification_text_margin_top);
}
@@ -696,10 +705,18 @@
mIsInConversation = isInConversation;
MarginLayoutParams layoutParams =
(MarginLayoutParams) mMessagingIconContainer.getLayoutParams();
- layoutParams.width = mIsInConversation ? mConversationContentStart
- : ViewPager.LayoutParams.WRAP_CONTENT;
- layoutParams.setMarginEnd(mIsInConversation ? 0 : mNonConversationMarginEnd);
+ layoutParams.width = mIsInConversation
+ ? mConversationContentStart
+ : mNonConversationContentStart;
mMessagingIconContainer.setLayoutParams(layoutParams);
+ int imagePaddingStart = isInConversation ? 0 : mNonConversationPaddingStart;
+ mMessagingIconContainer.setPaddingRelative(imagePaddingStart, 0, 0, 0);
+
+ ViewGroup.LayoutParams avatarLayoutParams = mAvatarView.getLayoutParams();
+ int size = mIsInConversation ? mConversationAvatarSize : mNonConversationAvatarSize;
+ avatarLayoutParams.height = size;
+ avatarLayoutParams.width = size;
+ mAvatarView.setLayoutParams(avatarLayoutParams);
}
}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 27cd6e1..e1602a9 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_AT_END;
+import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_EXTERNAL;
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_INLINE;
import android.annotation.AttrRes;
@@ -27,10 +27,6 @@
import android.app.Person;
import android.app.RemoteInputHistoryItem;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -40,21 +36,22 @@
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.RemoteViews;
-import android.widget.TextView;
import com.android.internal.R;
-import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.ContrastColorUtil;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.function.Consumer;
-import java.util.regex.Pattern;
/**
* A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
@@ -65,15 +62,6 @@
implements ImageMessageConsumer, IMessagingLayout {
private static final float COLOR_SHIFT_AMOUNT = 60;
- /**
- * Pattren for filter some ingonable characters.
- * p{Z} for any kind of whitespace or invisible separator.
- * p{C} for any kind of punctuation character.
- */
- private static final Pattern IGNORABLE_CHAR_PATTERN
- = Pattern.compile("[\\p{C}\\p{Z}]");
- private static final Pattern SPECIAL_CHAR_PATTERN
- = Pattern.compile ("[!@#$%&*()_+=|<>?{}\\[\\]~-]");
private static final Consumer<MessagingMessage> REMOVE_MESSAGE
= MessagingMessage::removeMessage;
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
@@ -81,26 +69,26 @@
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
= new MessagingPropertyAnimator();
+ private final PeopleHelper mPeopleHelper = new PeopleHelper();
private List<MessagingMessage> mMessages = new ArrayList<>();
private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
private MessagingLinearLayout mMessagingLinearLayout;
private boolean mShowHistoricMessages;
private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
- private TextView mTitleView;
+ private MessagingLinearLayout mImageMessageContainer;
+ private ImageView mRightIconView;
+ private Rect mMessagingClipRect;
private int mLayoutColor;
private int mSenderTextColor;
private int mMessageTextColor;
- private int mAvatarSize;
- private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private Paint mTextPaint = new Paint();
- private CharSequence mConversationTitle;
private Icon mAvatarReplacement;
private boolean mIsOneToOne;
private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
private Person mUser;
private CharSequence mNameReplacement;
- private boolean mDisplayImagesAtEnd;
+ private boolean mIsCollapsed;
private ImageResolver mImageResolver;
+ private CharSequence mConversationTitle;
public MessagingLayout(@NonNull Context context) {
super(context);
@@ -123,17 +111,16 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mPeopleHelper.init(getContext());
mMessagingLinearLayout = findViewById(R.id.notification_messaging);
+ mImageMessageContainer = findViewById(R.id.conversation_image_message_container);
+ mRightIconView = findViewById(R.id.right_icon);
// We still want to clip, but only on the top, since views can temporarily out of bounds
// during transitions.
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int size = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
- Rect rect = new Rect(0, 0, size, size);
- mMessagingLinearLayout.setClipBounds(rect);
- mTitleView = findViewById(R.id.title);
- mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
- mTextPaint.setTextAlign(Paint.Align.CENTER);
- mTextPaint.setAntiAlias(true);
+ mMessagingClipRect = new Rect(0, 0, size, size);
+ setMessagingClippingDisabled(false);
}
@RemotableViewMethod
@@ -153,7 +140,7 @@
*/
@RemotableViewMethod
public void setIsCollapsed(boolean isCollapsed) {
- mDisplayImagesAtEnd = isCollapsed;
+ mIsCollapsed = isCollapsed;
}
@RemotableViewMethod
@@ -168,7 +155,7 @@
*/
@RemotableViewMethod
public void setConversationTitle(CharSequence conversationTitle) {
- // Unused
+ mConversationTitle = conversationTitle;
}
@RemotableViewMethod
@@ -180,11 +167,6 @@
List<Notification.MessagingStyle.Message> newHistoricMessages
= Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
- mConversationTitle = null;
- TextView headerText = findViewById(R.id.header_text);
- if (headerText != null) {
- mConversationTitle = headerText.getText();
- }
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
addRemoteInputHistoryToMessages(newMessages, history);
@@ -238,6 +220,41 @@
updateHistoricMessageVisibility();
updateTitleAndNamesDisplay();
+ // after groups are finalized, hide the first sender name if it's showing as the title
+ mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, mConversationTitle);
+ updateImageMessages();
+ }
+
+ private void updateImageMessages() {
+ View newMessage = null;
+ if (mImageMessageContainer == null) {
+ return;
+ }
+ if (mIsCollapsed && !mGroups.isEmpty()) {
+ // When collapsed, we're displaying the image message in a dedicated container
+ // on the right of the layout instead of inline. Let's add the isolated image there
+ MessagingGroup messagingGroup = mGroups.get(mGroups.size() - 1);
+ MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage();
+ if (isolatedMessage != null) {
+ newMessage = isolatedMessage.getView();
+ }
+ }
+ // Remove all messages that don't belong into the image layout
+ View previousMessage = mImageMessageContainer.getChildAt(0);
+ if (previousMessage != newMessage) {
+ mImageMessageContainer.removeView(previousMessage);
+ if (newMessage != null) {
+ mImageMessageContainer.addView(newMessage);
+ }
+ }
+ mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE);
+
+ // When showing an image message, do not show the large icon. Removing the drawable
+ // prevents it from being shown in the left_icon view (by the grouping util).
+ if (newMessage != null && mRightIconView != null && mRightIconView.getDrawable() != null) {
+ mRightIconView.setImageDrawable(null);
+ mRightIconView.setVisibility(GONE);
+ }
}
private void removeGroups(ArrayList<MessagingGroup> oldGroups) {
@@ -266,34 +283,7 @@
}
private void updateTitleAndNamesDisplay() {
- ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
- ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
- for (int i = 0; i < mGroups.size(); i++) {
- MessagingGroup group = mGroups.get(i);
- CharSequence senderName = group.getSenderName();
- if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
- continue;
- }
- if (!uniqueNames.containsKey(senderName)) {
- // Only use visible characters to get uniqueNames
- String pureSenderName = IGNORABLE_CHAR_PATTERN
- .matcher(senderName).replaceAll("" /* replacement */);
- char c = pureSenderName.charAt(0);
- if (uniqueCharacters.containsKey(c)) {
- // this character was already used, lets make it more unique. We first need to
- // resolve the existing character if it exists
- CharSequence existingName = uniqueCharacters.get(c);
- if (existingName != null) {
- uniqueNames.put(existingName, findNameSplit((String) existingName));
- uniqueCharacters.put(c, null);
- }
- uniqueNames.put(senderName, findNameSplit((String) senderName));
- } else {
- uniqueNames.put(senderName, Character.toString(c));
- uniqueCharacters.put(c, pureSenderName);
- }
- }
- }
+ Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups);
// Now that we have the correct symbols, let's look what we have cached
ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
@@ -337,26 +327,7 @@
}
public Icon createAvatarSymbol(CharSequence senderName, String symbol, int layoutColor) {
- if (symbol.isEmpty() || TextUtils.isDigitsOnly(symbol) ||
- SPECIAL_CHAR_PATTERN.matcher(symbol).find()) {
- Icon avatarIcon = Icon.createWithResource(getContext(),
- com.android.internal.R.drawable.messaging_user);
- avatarIcon.setTint(findColor(senderName, layoutColor));
- return avatarIcon;
- } else {
- Bitmap bitmap = Bitmap.createBitmap(mAvatarSize, mAvatarSize, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- float radius = mAvatarSize / 2.0f;
- int color = findColor(senderName, layoutColor);
- mPaint.setColor(color);
- canvas.drawCircle(radius, radius, radius, mPaint);
- boolean needDarkText = ColorUtils.calculateLuminance(color) > 0.5f;
- mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE);
- mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.5f : mAvatarSize * 0.3f);
- int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2));
- canvas.drawText(symbol, radius, yPos, mTextPaint);
- return Icon.createWithBitmap(bitmap);
- }
+ return mPeopleHelper.createAvatarSymbol(senderName, symbol, layoutColor);
}
private int findColor(CharSequence senderName, int layoutColor) {
@@ -449,8 +420,8 @@
newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
mAddedGroups.add(newGroup);
}
- newGroup.setImageDisplayLocation(mDisplayImagesAtEnd
- ? IMAGE_DISPLAY_LOCATION_AT_END
+ newGroup.setImageDisplayLocation(mIsCollapsed
+ ? IMAGE_DISPLAY_LOCATION_EXTERNAL
: IMAGE_DISPLAY_LOCATION_INLINE);
newGroup.setIsInConversation(false);
newGroup.setLayoutColor(mLayoutColor);
@@ -460,6 +431,8 @@
if (sender != mUser && mNameReplacement != null) {
nameOverride = mNameReplacement;
}
+ newGroup.setSingleLine(mIsCollapsed);
+ newGroup.setShowingAvatar(!mIsCollapsed);
newGroup.setSender(sender, nameOverride);
newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
mGroups.add(newGroup);
@@ -600,12 +573,17 @@
return mMessagingLinearLayout;
}
+ @Nullable
+ public ViewGroup getImageMessageContainer() {
+ return mImageMessageContainer;
+ }
+
public ArrayList<MessagingGroup> getMessagingGroups() {
return mGroups;
}
@Override
public void setMessagingClippingDisabled(boolean clippingDisabled) {
- // Don't do anything, this is only used for the ConversationLayout
+ mMessagingLinearLayout.setClipBounds(clippingDisabled ? null : mMessagingClipRect);
}
}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 7a8ead6..de3b6a4 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -165,15 +165,23 @@
private void updateColors() {
if (shouldShowNumber() && !mDisallowColor) {
- mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
+ if (mHighlightPillColor != 0) {
+ mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
+ }
mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN);
mIconView.setColorFilter(mHighlightTextColor, PorterDuff.Mode.SRC_IN);
- mNumberView.setTextColor(mHighlightTextColor);
+ if (mHighlightTextColor != 0) {
+ mNumberView.setTextColor(mHighlightTextColor);
+ }
} else {
- mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
+ if (mDefaultPillColor != 0) {
+ mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
+ }
mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN);
mIconView.setColorFilter(mDefaultTextColor, PorterDuff.Mode.SRC_IN);
- mNumberView.setTextColor(mDefaultTextColor);
+ if (mDefaultTextColor != 0) {
+ mNumberView.setTextColor(mDefaultTextColor);
+ }
}
}
diff --git a/core/java/com/android/internal/widget/PeopleHelper.java b/core/java/com/android/internal/widget/PeopleHelper.java
index 77f4c8f..85cedc3 100644
--- a/core/java/com/android/internal/widget/PeopleHelper.java
+++ b/core/java/com/android/internal/widget/PeopleHelper.java
@@ -21,6 +21,7 @@
import android.annotation.ColorInt;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -28,12 +29,15 @@
import android.graphics.Paint;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.view.View;
import com.android.internal.R;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.ContrastColorUtil;
+import java.util.List;
+import java.util.Map;
import java.util.regex.Pattern;
/**
@@ -176,4 +180,58 @@
}
return findNamePrefix(name, "");
}
+
+ /**
+ * Creates a mapping of the unique sender names in the groups to the string 1- or 2-character
+ * prefix strings for the names, which are extracted as the initials, and should be used for
+ * generating the avatar. Senders not requiring a generated avatar, or with an empty name are
+ * omitted.
+ */
+ public Map<CharSequence, String> mapUniqueNamesToPrefix(List<MessagingGroup> groups) {
+ // Map of unique names to their prefix
+ ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
+ // Map of single-character string prefix to the only name which uses it, or null if multiple
+ ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>();
+ for (int i = 0; i < groups.size(); i++) {
+ MessagingGroup group = groups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
+ continue;
+ }
+ if (!uniqueNames.containsKey(senderName)) {
+ String charPrefix = findNamePrefix(senderName, null);
+ if (charPrefix == null) {
+ continue;
+ }
+ if (uniqueCharacters.containsKey(charPrefix)) {
+ // this character was already used, lets make it more unique. We first need to
+ // resolve the existing character if it exists
+ CharSequence existingName = uniqueCharacters.get(charPrefix);
+ if (existingName != null) {
+ uniqueNames.put(existingName, findNameSplit(existingName));
+ uniqueCharacters.put(charPrefix, null);
+ }
+ uniqueNames.put(senderName, findNameSplit(senderName));
+ } else {
+ uniqueNames.put(senderName, charPrefix);
+ uniqueCharacters.put(charPrefix, senderName);
+ }
+ }
+ }
+ return uniqueNames;
+ }
+
+ /**
+ * Update whether the groups can hide the sender if they are first
+ * (happens only for 1:1 conversations where the given title matches the sender's name)
+ */
+ public void maybeHideFirstSenderName(@NonNull List<MessagingGroup> groups,
+ boolean isOneToOne, @Nullable CharSequence conversationTitle) {
+ for (int i = groups.size() - 1; i >= 0; i--) {
+ MessagingGroup messagingGroup = groups.get(i);
+ CharSequence messageSender = messagingGroup.getSenderName();
+ boolean canHide = isOneToOne && TextUtils.equals(conversationTitle, messageSender);
+ messagingGroup.setCanHideSenderIfFirst(canHide);
+ }
+ }
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b342755..ffba628 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1562,6 +1562,13 @@
reinterpret_cast<SurfaceComposerClient::Transaction *>(nativeObject);
if (self != nullptr) {
self->writeToParcel(parcel);
+ }
+}
+
+static void nativeClearTransaction(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ SurfaceComposerClient::Transaction* const self =
+ reinterpret_cast<SurfaceComposerClient::Transaction*>(nativeObject);
+ if (self != nullptr) {
self->clear();
}
}
@@ -1880,6 +1887,8 @@
(void*)nativeReadTransactionFromParcel },
{"nativeWriteTransactionToParcel", "(JLandroid/os/Parcel;)V",
(void*)nativeWriteTransactionToParcel },
+ {"nativeClearTransaction", "(J)V",
+ (void*)nativeClearTransaction },
{"nativeMirrorSurface", "(J)J",
(void*)nativeMirrorSurface },
{"nativeSetGlobalShadowSettings", "([F[FFFF)V",
diff --git a/core/proto/android/internal/binder_latency.proto b/core/proto/android/internal/binder_latency.proto
new file mode 100644
index 0000000..e32c3e3
--- /dev/null
+++ b/core/proto/android/internal/binder_latency.proto
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package com.android.internal.os;
+
+option java_outer_classname = "BinderLatencyProto";
+
+/**
+ * RepeatedApiStats proto from atoms.proto, duplicated here so that it's
+ * accessible in the build.
+ * Must be kept in sync with the version in atoms.proto.
+ */
+
+message RepeatedApiStats {
+ repeated ApiStats api_stats = 1;
+}
+
+message Dims {
+ enum ProcessSource {
+ UNKNOWN_PROCESS_SOURCE = 0;
+ SYSTEM_SERVER = 1;
+ TELEPHONY = 2;
+ }
+
+ enum ServiceClassName {
+ UNKNOWN_CLASS = 0;
+ }
+ enum ServiceMethodName {
+ UNKNOWN_METHOD = 0;
+ }
+
+ // Required.
+ optional ProcessSource process_source = 1;
+
+ // The class name of the API making the call to Binder. Enum value
+ // is preferred as uses much less data to store.
+ // This field does not contain PII.
+ oneof service_class {
+ ServiceClassName service_class_name_as_enum = 2;
+ string service_class_name = 3;
+ }
+
+ // Method name of the API call. It can also be a transaction code if we
+ // cannot resolve it to a name. See Binder#getTransactionName. Enum value
+ // is preferred as uses much less data to store.
+ // This field does not contain PII.
+ oneof service_method {
+ ServiceMethodName service_method_name_as_enum = 4;
+ string service_method_name = 5;
+ }
+}
+
+message ApiStats {
+ // required.
+ optional Dims dims = 1;
+
+ // Indicates the first bucket that had any data. Allows omitting any empty
+ // buckets at the start of the bucket list and thus save on data size.
+ optional int32 first_bucket_index = 2;
+ // Stores the count of samples for each bucket. The number of buckets and
+ // their sizes are controlled server side with a flag.
+ repeated int32 buckets = 3;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index a7127ad..b157146 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -308,6 +308,7 @@
optional float minimize_amount = 27;
optional bool created_by_organizer = 28;
optional string affinity = 29;
+ optional bool has_child_pip_activity = 30;
}
/* represents ActivityRecordProto */
diff --git a/core/res/res/drawable/ic_call_answer_video.xml b/core/res/res/drawable/ic_call_answer_video.xml
new file mode 100644
index 0000000..77c8892
--- /dev/null
+++ b/core/res/res/drawable/ic_call_answer_video.xml
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20"
+ android:tint="?android:attr/colorControlNormal"
+ android:autoMirrored="true">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15,8v8H5V8h10m1,-2H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0
+ 1,-0.45 1,-1v-3.5l4,4v-11l-4,4V7c0,-0.55 -0.45,-1 -1,-1z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_expand_button.xml b/core/res/res/layout/notification_expand_button.xml
index b969fa4..e752431 100644
--- a/core/res/res/layout/notification_expand_button.xml
+++ b/core/res/res/layout/notification_expand_button.xml
@@ -22,7 +22,6 @@
android:layout_gravity="top|end"
android:contentDescription="@string/expand_button_content_description_collapsed"
android:padding="16dp"
- android:visibility="gone"
>
<LinearLayout
@@ -40,6 +39,7 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
android:gravity="center_vertical"
android:paddingStart="8dp"
+ android:visibility="gone"
/>
<ImageView
diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml
index e01d803..389637eb 100644
--- a/core/res/res/layout/notification_template_conversation_header.xml
+++ b/core/res/res/layout/notification_template_conversation_header.xml
@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingTop="16dp"
+ android:paddingTop="20dp"
>
<TextView
@@ -42,8 +42,6 @@
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
- android:layout_gravity="center"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -54,10 +52,8 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -70,8 +66,6 @@
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
- android:layout_gravity="center"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -81,9 +75,7 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
- android:paddingTop="1sp"
android:showRelative="true"
android:singleLine="true"
android:visibility="gone"
@@ -93,7 +85,6 @@
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout="@layout/notification_template_part_chronometer"
android:visibility="gone"
@@ -107,8 +98,6 @@
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
- android:layout_gravity="center"
- android:paddingTop="1sp"
android:singleLine="true"
android:visibility="gone"
/>
@@ -117,9 +106,8 @@
android:id="@+id/verification_icon"
android:layout_width="@dimen/notification_verification_icon_size"
android:layout_height="@dimen/notification_verification_icon_size"
- android:layout_gravity="center"
android:layout_marginStart="4dp"
- android:paddingTop="2dp"
+ android:baseline="10dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_notifications_alerted"
android:visibility="gone"
@@ -130,9 +118,7 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
- android:paddingTop="1sp"
android:showRelative="true"
android:singleLine="true"
android:visibility="gone"
@@ -142,11 +128,10 @@
android:id="@+id/feedback"
android:layout_width="@dimen/notification_feedback_size"
android:layout_height="@dimen/notification_feedback_size"
- android:layout_gravity="center"
android:layout_marginStart="@dimen/notification_header_separating_margin"
android:background="?android:selectableItemBackgroundBorderless"
android:contentDescription="@string/notification_feedback_indicator"
- android:paddingTop="2dp"
+ android:baseline="13dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_feedback_indicator"
android:visibility="gone"
@@ -157,21 +142,19 @@
android:layout_width="@dimen/notification_phishing_alert_size"
android:layout_height="@dimen/notification_phishing_alert_size"
android:layout_marginStart="4dp"
- android:paddingTop="2dp"
+ android:baseline="10dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_dialog_alert_material"
android:visibility="gone"
android:contentDescription="@string/notification_phishing_alert_content_description"
/>
-
<ImageView
android:id="@+id/profile_badge"
android:layout_width="@dimen/notification_badge_size"
android:layout_height="@dimen/notification_badge_size"
- android:layout_gravity="center"
android:layout_marginStart="4dp"
- android:paddingTop="2dp"
+ android:baseline="10dp"
android:scaleType="fitCenter"
android:visibility="gone"
android:contentDescription="@string/notification_work_profile_content_description"
@@ -181,10 +164,9 @@
android:id="@+id/alerted_icon"
android:layout_width="@dimen/notification_alerted_size"
android:layout_height="@dimen/notification_alerted_size"
- android:layout_gravity="center"
android:layout_marginStart="4dp"
+ android:baseline="10dp"
android:contentDescription="@string/notification_alerted_content_description"
- android:paddingTop="2dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_notifications_alerted"
android:visibility="gone"
diff --git a/core/res/res/layout/notification_template_conversation_icon_container.xml b/core/res/res/layout/notification_template_conversation_icon_container.xml
index e9ec7ce..a88ff0d 100644
--- a/core/res/res/layout/notification_template_conversation_icon_container.xml
+++ b/core/res/res/layout/notification_template_conversation_icon_container.xml
@@ -23,8 +23,8 @@
android:gravity="start|top"
android:clipChildren="false"
android:clipToPadding="false"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
+ android:paddingTop="20dp"
+ android:paddingBottom="16dp"
android:importantForAccessibility="no"
>
diff --git a/core/res/res/layout/notification_template_material_big_messaging.xml b/core/res/res/layout/notification_template_material_big_messaging.xml
new file mode 100644
index 0000000..01c37b7
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_big_messaging.xml
@@ -0,0 +1,62 @@
+<?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
+ -->
+<com.android.internal.widget.MessagingLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ android:tag="messaging"
+ >
+ <include layout="@layout/notification_template_header"/>
+ <com.android.internal.widget.RemeasuringLinearLayout
+ android:id="@+id/notification_action_list_margin_target"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:clipChildren="false"
+ android:orientation="vertical">
+
+ <com.android.internal.widget.RemeasuringLinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:layout_weight="1"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ >
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/notification_messaging"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:spacing="@dimen/notification_messaging_spacing" />
+ </com.android.internal.widget.RemeasuringLinearLayout>
+ <include layout="@layout/notification_template_smart_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_content_margin"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end" />
+ <include layout="@layout/notification_material_action_list" />
+ </com.android.internal.widget.RemeasuringLinearLayout>
+ <include layout="@layout/notification_template_right_icon" />
+</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_template_material_call.xml b/core/res/res/layout/notification_template_material_call.xml
index 5d9e761..1b3bd26 100644
--- a/core/res/res/layout/notification_template_material_call.xml
+++ b/core/res/res/layout/notification_template_material_call.xml
@@ -29,7 +29,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="80dp"
+ android:layout_height="88dp"
android:orientation="horizontal"
>
diff --git a/core/res/res/layout/notification_template_material_heads_up_base.xml b/core/res/res/layout/notification_template_material_heads_up_base.xml
index d554991..a0d19b4 100644
--- a/core/res/res/layout/notification_template_material_heads_up_base.xml
+++ b/core/res/res/layout/notification_template_material_heads_up_base.xml
@@ -38,7 +38,7 @@
<com.android.internal.widget.RemeasuringLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="-12dp"
+ android:layout_marginTop="-20dp"
android:clipChildren="false"
android:orientation="vertical"
>
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index c3fd249..3564f97 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -22,32 +22,186 @@
android:clipChildren="false"
android:tag="messaging"
>
- <include layout="@layout/notification_template_header"/>
- <com.android.internal.widget.RemeasuringLinearLayout
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:orientation="vertical"
+ >
+
+
+ <com.android.internal.widget.NotificationMaxHeightFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_min_height"
+ android:clipChildren="false"
+ >
+
+ <ImageView
+ android:id="@+id/left_icon"
+ android:layout_width="@dimen/notification_left_icon_size"
+ android:layout_height="@dimen/notification_left_icon_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_left_icon_start"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:visibility="gone"
+ />
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_icon_circle_size"
+ android:layout_height="@dimen/notification_icon_circle_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:padding="@dimen/notification_icon_circle_padding"
+ />
+
+ <FrameLayout
+ android:id="@+id/alternate_expand_target"
+ android:layout_width="@dimen/notification_content_margin_start"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:importantForAccessibility="no"
+ />
+
+ <!--
+ NOTE: to make the expansion animation of id/notification_messaging happen vertically,
+ its X positioning must be the left edge of the notification, so instead of putting the
+ layout_marginStart on the id/notification_headerless_view_row, we put it on
+ id/notification_top_line, making the layout here just a bit different from the base.
+ -->
+ <LinearLayout
+ android:id="@+id/notification_headerless_view_row"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ >
+
+ <!--
+ NOTE: because messaging will always have 2 lines, this LinearLayout should NOT
+ have the id/notification_headerless_view_column, as that is used for modifying
+ vertical margins to accommodate the single-line state that base supports
+ -->
+ <LinearLayout
+ android:layout_width="0px"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+ android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+ android:clipChildren="false"
+ android:orientation="vertical"
+ >
+
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:clipChildren="false"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ >
+
+ <!--
+ NOTE: The notification_top_line_views layout contains the app_name_text.
+ In order to include the title view at the beginning, the Notification.Builder
+ has logic to hide that view whenever this title view is to be visible.
+ -->
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+ />
+
+ <include layout="@layout/notification_top_line_views" />
+
+ </NotificationTopLineView>
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ >
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/notification_messaging"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:spacing="@dimen/notification_messaging_spacing" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <!-- Images -->
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/conversation_image_message_container"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+ android:forceHasOverlappingRendering="false"
+ android:spacing="0dp"
+ android:clipChildren="false"
+ android:visibility="gone"
+ />
+
+ <ImageView
+ android:id="@+id/right_icon"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+ android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+ android:background="@drawable/notification_large_icon_outline"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ />
+
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+ </com.android.internal.widget.NotificationMaxHeightFrameLayout>
+
+ <LinearLayout
android:id="@+id/notification_action_list_margin_target"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:clipToPadding="false"
+ android:layout_marginTop="-20dp"
+ android:clipChildren="false"
android:orientation="vertical">
-
- <com.android.internal.widget.RemeasuringLinearLayout
- android:id="@+id/notification_main_column"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:orientation="vertical"
- >
- <com.android.internal.widget.MessagingLinearLayout
- android:id="@+id/notification_messaging"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:spacing="@dimen/notification_messaging_spacing" />
- </com.android.internal.widget.RemeasuringLinearLayout>
<include layout="@layout/notification_template_smart_reply_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -55,6 +209,6 @@
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end" />
<include layout="@layout/notification_material_action_list" />
- </com.android.internal.widget.RemeasuringLinearLayout>
- <include layout="@layout/notification_template_right_icon" />
+ </LinearLayout>
+</LinearLayout>
</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_top_line_views.xml b/core/res/res/layout/notification_top_line_views.xml
index 88bcc4d..8284279 100644
--- a/core/res/res/layout/notification_top_line_views.xml
+++ b/core/res/res/layout/notification_top_line_views.xml
@@ -113,11 +113,10 @@
android:layout_width="@dimen/notification_feedback_size"
android:layout_height="@dimen/notification_feedback_size"
android:layout_marginStart="@dimen/notification_header_separating_margin"
- android:layout_gravity="center"
+ android:baseline="13dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_feedback_indicator"
android:background="?android:selectableItemBackgroundBorderless"
- android:paddingTop="2dp"
android:visibility="gone"
android:contentDescription="@string/notification_feedback_indicator"
/>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c51b2d8..588ae79 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -826,7 +826,7 @@
that created the task, and therefore there will only be one instance of this activity
in a task. In constrast to the {@code singleTask} launch mode, this activity can be
started in multiple instances in different tasks if the
- {@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.-->
+ {@code FLAG_ACTIVITY_MULTIPLE_TASK} or {@code FLAG_ACTIVITY_NEW_DOCUMENT} is set.-->
<enum name="singleInstancePerTask" value="4" />
</attr>
<!-- Specify the orientation an activity should be run in. If not
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e4ea8fb..f24d663 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1772,6 +1772,9 @@
<!-- Add algorithm here -->
</string-array>
+ <!-- Boolean indicating if placing the phone face down will result in a screen off. -->
+ <bool name="config_flipToScreenOffEnabled">true</bool>
+
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
@@ -3721,13 +3724,6 @@
-->
<string name="config_defaultWellbeingPackage" translatable="false"></string>
- <!-- The package name for the companion provider app.
- This package must be trusted, as it has the permissions to associate apps with devices
- without a UI prompt.
- Example: "com.google.android.gms"
- -->
- <string name="config_companionProviderPackage" translatable="false"></string>
-
<!-- The component name for the default system attention service.
This service must be trusted, as it can be activated without explicit consent of the user.
See android.attention.AttentionManagerService.
@@ -4704,6 +4700,11 @@
-->
<color name="config_letterboxBackgroundColor">#000</color>
+ <!-- Horizonal position of a center of the letterboxed app window.
+ 0 corresponds to the left side of the screen and 1 to the right side. If given value < 0
+ or > 1, it is ignored and central positionis used (0.5). -->
+ <item name="config_letterboxHorizontalPositionMultiplier" format="float" type="dimen">0.5</item>
+
<!-- If true, hide the display cutout with display area -->
<bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
@@ -4861,4 +4862,6 @@
<string name="config_systemTextIntelligence" translatable="false"></string>
<!-- On-device intelligent processor for visual features. -->
<string name="config_systemVisualIntelligence" translatable="false"></string>
+ <!-- On-device package for providing companion device associations. -->
+ <string name="config_systemCompanionDeviceProvider" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index fc2645c..0e436e3 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -758,23 +758,23 @@
<dimen name="notification_grayscale_icon_max_size">256dp</dimen>
<dimen name="messaging_avatar_size">36dp</dimen>
- <dimen name="conversation_avatar_size">52dp</dimen>
+ <dimen name="conversation_avatar_size">48dp</dimen>
<!-- start margin of the icon circle in the conversation's skin of the header -->
<dimen name="conversation_icon_circle_start">28dp</dimen>
<!-- Start of the content in the conversation template -->
<dimen name="conversation_content_start">80dp</dimen>
<!-- Height of the expand button in the conversation layout -->
- <dimen name="conversation_expand_button_height">80dp</dimen>
+ <dimen name="conversation_expand_button_height">88dp</dimen>
<!-- this is the margin between the Conversation image and the content -->
<dimen name="conversation_image_start_margin">12dp</dimen>
<!-- Side margins of the conversation badge in relation to the conversation icon -->
- <dimen name="conversation_badge_side_margin">36dp</dimen>
+ <dimen name="conversation_badge_side_margin">32dp</dimen>
<!-- size of the notification badge when applied to the conversation icon -->
<dimen name="conversation_icon_size_badged">20dp</dimen>
<!-- size of the conversation avatar in an expanded group -->
<dimen name="conversation_avatar_size_group_expanded">@dimen/messaging_avatar_size</dimen>
<!-- size of the face pile icons -->
- <dimen name="conversation_face_pile_avatar_size">@dimen/messaging_avatar_size</dimen>
+ <dimen name="conversation_face_pile_avatar_size">32dp</dimen>
<!-- size of the face pile icons when the group is expanded -->
<dimen name="conversation_face_pile_avatar_size_group_expanded">25dp</dimen>
<!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded-->
@@ -795,7 +795,7 @@
<dimen name="importance_ring_size">20dp</dimen>
<!-- The top padding of the conversation icon container in the regular state-->
- <dimen name="conversation_icon_container_top_padding">12dp</dimen>
+ <dimen name="conversation_icon_container_top_padding">20dp</dimen>
<!-- The top padding of the conversation icon container when the avatar is small-->
<dimen name="conversation_icon_container_top_padding_small_avatar">9dp</dimen>
@@ -803,8 +803,8 @@
<!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
<dimen name="conversation_header_expanded_padding_end">38dp</dimen>
- <!-- margin at the end of messaging group icons when not conversations -->
- <dimen name="messaging_layout_margin_end">12dp</dimen>
+ <!-- extra padding at the start of the icons when not conversations to keep them horizontally aligned with the notification icon -->
+ <dimen name="messaging_layout_icon_padding_start">4dp</dimen>
<!-- Padding between text and sender when singleline -->
<dimen name="messaging_group_singleline_sender_padding_end">4dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 89adc8c..f6a67d2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3225,6 +3225,8 @@
<public name="config_systemVisualIntelligence" />
<!-- @hide @SystemApi -->
<public name="config_systemActivityRecognizer" />
+ <!-- @hide @SystemApi -->
+ <public name="config_systemCompanionDeviceProvider"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01020055">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3208dff..8d07ae2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5151,6 +5151,8 @@
<!-- Action text to be displayed for the "answer" action of an incoming call [CHAR LIMIT=13] -->
<string name="call_notification_answer_action">Answer</string>
+ <!-- Action text to be displayed for the "answer" action of an incoming VIDEO call [CHAR LIMIT=13] -->
+ <string name="call_notification_answer_video_action">Video</string>
<!-- Action text to be displayed for the "decline" action of an incoming call [CHAR LIMIT=13] -->
<string name="call_notification_decline_action">Decline</string>
<!-- Action text to be displayed for the "hang up" action of an ongoing call [CHAR LIMIT=13] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4bb3236..5715fab 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -275,6 +275,7 @@
<java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
<java-symbol type="bool" name="config_avoidGfxAccel" />
<java-symbol type="bool" name="config_bluetooth_address_validation" />
+ <java-symbol type="bool" name="config_flipToScreenOffEnabled" />
<java-symbol type="bool" name="config_bluetooth_sco_off_call" />
<java-symbol type="bool" name="config_bluetooth_le_peripheral_mode_supported" />
<java-symbol type="bool" name="config_bluetooth_hfp_inband_ringing_support" />
@@ -3015,6 +3016,7 @@
<java-symbol type="layout" name="app_anr_dialog" />
<java-symbol type="layout" name="notification_template_material_messaging" />
+ <java-symbol type="layout" name="notification_template_material_big_messaging" />
<java-symbol type="id" name="aerr_wait" />
@@ -3115,6 +3117,7 @@
<java-symbol type="layout" name="notification_template_material_call" />
<java-symbol type="layout" name="notification_template_material_big_call" />
<java-symbol type="string" name="call_notification_answer_action" />
+ <java-symbol type="string" name="call_notification_answer_video_action" />
<java-symbol type="string" name="call_notification_decline_action" />
<java-symbol type="string" name="call_notification_hang_up_action" />
<java-symbol type="string" name="call_notification_incoming_text" />
@@ -3124,6 +3127,7 @@
<java-symbol type="color" name="call_notification_answer_color"/>
<java-symbol type="dimen" name="call_notification_collapsible_indent"/>
<java-symbol type="drawable" name="ic_call_answer" />
+ <java-symbol type="drawable" name="ic_call_answer_video" />
<java-symbol type="drawable" name="ic_call_decline" />
<java-symbol type="id" name="verification_divider" />
<java-symbol type="id" name="verification_icon" />
@@ -3537,7 +3541,6 @@
<java-symbol type="string" name="notification_channel_do_not_disturb" />
<java-symbol type="string" name="notification_channel_accessibility_magnification" />
<java-symbol type="string" name="notification_channel_accessibility_security_policy" />
- <java-symbol type="string" name="config_companionProviderPackage" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultOnDeviceSpeechRecognitionService" />
<java-symbol type="string" name="config_defaultTextClassifierPackage" />
@@ -3646,6 +3649,7 @@
<java-symbol type="id" name="bubble_button" />
<java-symbol type="id" name="snooze_button" />
<java-symbol type="dimen" name="text_size_body_2_material" />
+ <java-symbol type="dimen" name="notification_icon_circle_size" />
<java-symbol type="dimen" name="messaging_avatar_size" />
<java-symbol type="dimen" name="messaging_group_sending_progress_size" />
<java-symbol type="dimen" name="messaging_image_rounding" />
@@ -4062,7 +4066,7 @@
<java-symbol type="dimen" name="conversation_badge_side_margin_group_expanded_face_pile" />
<java-symbol type="dimen" name="conversation_content_start" />
<java-symbol type="dimen" name="expanded_group_conversation_message_padding" />
- <java-symbol type="dimen" name="messaging_layout_margin_end" />
+ <java-symbol type="dimen" name="messaging_layout_icon_padding_start" />
<java-symbol type="dimen" name="conversation_header_expanded_padding_end" />
<java-symbol type="dimen" name="conversation_icon_container_top_padding" />
<java-symbol type="dimen" name="conversation_icon_container_top_padding_small_avatar" />
@@ -4182,6 +4186,7 @@
<java-symbol type="dimen" name="config_letterboxBackgroundWallaperDarkScrimAlpha" />
<java-symbol type="integer" name="config_letterboxBackgroundType" />
<java-symbol type="color" name="config_letterboxBackgroundColor" />
+ <java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" />
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
@@ -4336,4 +4341,6 @@
<java-symbol type="drawable" name="ic_accessibility_24dp" />
<java-symbol type="string" name="view_and_control_notification_title" />
<java-symbol type="string" name="view_and_control_notification_content" />
+
+ <java-symbol type="layout" name="notification_expand_button"/>
</resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_amp_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_amp_24.xml
new file mode 100644
index 0000000..1f57318
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_amp_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="#d14d2c">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11.17,19.5h-0.83l0.82,-5.83 -4.18,0.01 5.85,-9.17h0.83l-0.84,5.84h4.17l-5.82,9.15z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_calculate_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_calculate_24.xml
new file mode 100644
index 0000000..70aac32
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_calculate_24.xml
@@ -0,0 +1,25 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="#269e5c">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.25,7.72h5v1.5h-5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,15.75h5v1.5h-5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,13.25h5v1.5h-5z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M8,18l1.5,0l0,-2l2,0l0,-1.5l-2,0l0,-2l-1.5,0l0,2l-2,0l0,1.5l2,0z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.09,10.95l1.41,-1.41l1.41,1.41l1.06,-1.06l-1.41,-1.42l1.41,-1.41l-1.06,-1.06l-1.41,1.41l-1.41,-1.41l-1.06,1.06l1.41,1.41l-1.41,1.42z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_custom_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_custom_24.xml
new file mode 100644
index 0000000..39f9689
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_custom_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="#d14d2c">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,9L22,7h-2L20,5c0,-1.1 -0.9,-2 -2,-2L4,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-2h2v-2h-2v-2h2v-2h-2L20,9h2zM18,19L4,19L4,5h14v14zM6,13h5v4L6,17v-4zM12,7h4v3h-4L12,7zM6,7h5v5L6,12L6,7zM12,11h4v6h-4v-6z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_timer_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_timer_24.xml
new file mode 100644
index 0000000..9cae545
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_timer_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,3L9,3L9,1h6v2zM11,14h2L13,8h-2v6zM21,13.01c0,4.97 -4.02,9 -9,9s-9,-4.03 -9,-9 4.03,-9 9,-9c2.12,0 4.07,0.74 5.62,1.98l1.42,-1.42c0.51,0.42 0.98,0.9 1.41,1.41L19.03,7.4C20.26,8.93 21,10.89 21,13.01zM19,13.01c0,-3.87 -3.13,-7 -7,-7s-7,3.13 -7,7 3.13,7 7,7 7,-3.13 7,-7z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
index 1ced825..98fc581 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
@@ -25,6 +25,13 @@
android:paddingTop="8dp"
android:paddingBottom="8dp">
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="8dp"/>
+
<TextView
android:id="@+id/title"
android:layout_width="0dp"
@@ -34,16 +41,18 @@
<TextView
android:id="@+id/amount"
- android:layout_width="0dp"
- android:layout_weight="0.7"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
android:gravity="right"
+ android:maxLines="1"
android:textAppearance="@style/TextAppearanceBody"/>
<TextView
android:id="@+id/percent"
- android:layout_width="64dp"
+ android:layout_width="76dp"
android:layout_height="wrap_content"
android:gravity="right"
+ android:maxLines="1"
android:textAppearance="@style/TextAppearanceBody"/>
</LinearLayout>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
index e58a08f..24d193c4 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
@@ -43,10 +43,40 @@
android:paddingEnd="10dp">
<include layout="@layout/battery_consumer_info_layout"/>
-
</LinearLayout>
+
</androidx.cardview.widget.CardView>
+
+ <LinearLayout
+ android:id="@+id/headings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dp"
+ android:paddingBottom="4dp">
+ <FrameLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+ <TextView
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingEnd="10dp"
+ android:text="Total"/>
+ <TextView
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingEnd="30dp"
+ android:text="Apps"/>
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray"/>
+
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/battery_consumer_data_view"
android:layout_width="match_parent"
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.xml
new file mode 100644
index 0000000..2dbe48b
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/values/colors.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>
+ <color name="battery_consumer_bg_power_profile">#ffffff</color>
+ <color name="battery_consumer_bg_measured_energy">#fff5eb</color>
+</resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index 78569bd..f7d7098 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -18,32 +18,21 @@
import android.content.Context;
import android.os.BatteryConsumer;
-import android.os.BatteryStats;
import android.os.BatteryUsageStats;
-import android.os.Process;
import android.os.SystemBatteryConsumer;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
-
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
+import android.util.DebugUtils;
import java.util.ArrayList;
import java.util.List;
public class BatteryConsumerData {
- private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
- private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media";
- private static final String PACKAGE_SYSTEMUI = "com.android.systemui";
- private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
- PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
-
- // Unit conversion:
- // mAh = uC * (1/1000)(milli/micro) * (1/3600)(hours/second)
- private static final double UC_2_MAH = (1.0 / 1000) * (1.0 / 3600);
enum EntryType {
- POWER,
+ POWER_MODELED,
+ POWER_MEASURED,
+ POWER_CUSTOM,
DURATION,
}
@@ -52,268 +41,155 @@
public EntryType entryType;
public double value;
public double total;
+ public boolean isSystemBatteryConsumer;
}
private final BatteryConsumerInfoHelper.BatteryConsumerInfo mBatteryConsumerInfo;
private final List<Entry> mEntries = new ArrayList<>();
- public BatteryConsumerData(Context context, BatteryStatsHelper batteryStatsHelper,
+ public BatteryConsumerData(Context context,
List<BatteryUsageStats> batteryUsageStatsList, String batteryConsumerId) {
BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0);
- BatteryUsageStats powerProfileModeledUsageStats = batteryUsageStatsList.get(1);
- List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
- BatteryStats batteryStats = batteryStatsHelper.getStats();
+ BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1);
- double totalPowerMah = 0;
- double totalSmearedPowerMah = 0;
- double totalPowerExcludeSystemMah = 0;
- double totalScreenPower = 0;
- double totalProportionalSmearMah = 0;
- double totalCpuPowerMah = 0;
- double totalSystemServiceCpuPowerMah = 0;
- double totalUsagePowerMah = 0;
- double totalWakeLockPowerMah = 0;
- double totalMobileRadioPowerMah = 0;
- double totalWifiPowerMah = 0;
- double totalBluetoothPowerMah = 0;
- double totalGpsPowerMah = 0;
- double totalCameraPowerMah = 0;
- double totalFlashlightPowerMah = 0;
- double totalSensorPowerMah = 0;
- double totalAudioPowerMah = 0;
- double totalVideoPowerMah = 0;
+ BatteryConsumer requestedBatteryConsumer = getRequestedBatteryConsumer(batteryUsageStats,
+ batteryConsumerId);
+ BatteryConsumer requestedModeledBatteryConsumer = getRequestedBatteryConsumer(
+ modeledBatteryUsageStats, batteryConsumerId);
- long totalCpuTimeMs = 0;
- long totalCpuFgTimeMs = 0;
- long totalWakeLockTimeMs = 0;
- long totalWifiRunningTimeMs = 0;
- long totalBluetoothRunningTimeMs = 0;
- long totalGpsTimeMs = 0;
- long totalCameraTimeMs = 0;
- long totalFlashlightTimeMs = 0;
- long totalAudioTimeMs = 0;
- long totalVideoTimeMs = 0;
-
- BatterySipper requestedBatterySipper = null;
- for (BatterySipper sipper : usageList) {
- if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
- totalScreenPower = sipper.sumPower();
- }
-
- if (batteryConsumerId(sipper).equals(batteryConsumerId)) {
- requestedBatterySipper = sipper;
- }
-
- totalPowerMah += sipper.sumPower();
- totalSmearedPowerMah += sipper.totalSmearedPowerMah;
- totalProportionalSmearMah += sipper.proportionalSmearMah;
-
- if (!isSystemSipper(sipper)) {
- totalPowerExcludeSystemMah += sipper.totalSmearedPowerMah;
- }
-
- totalCpuPowerMah += sipper.cpuPowerMah;
- totalSystemServiceCpuPowerMah += sipper.systemServiceCpuPowerMah;
- totalUsagePowerMah += sipper.usagePowerMah;
- totalWakeLockPowerMah += sipper.wakeLockPowerMah;
- totalMobileRadioPowerMah += sipper.mobileRadioPowerMah;
- totalWifiPowerMah += sipper.wifiPowerMah;
- totalBluetoothPowerMah += sipper.bluetoothPowerMah;
- totalGpsPowerMah += sipper.gpsPowerMah;
- totalCameraPowerMah += sipper.cameraPowerMah;
- totalFlashlightPowerMah += sipper.flashlightPowerMah;
- totalSensorPowerMah += sipper.sensorPowerMah;
- totalAudioPowerMah += sipper.audioPowerMah;
- totalVideoPowerMah += sipper.videoPowerMah;
-
- totalCpuTimeMs += sipper.cpuTimeMs;
- totalCpuFgTimeMs += sipper.cpuFgTimeMs;
- totalWakeLockTimeMs += sipper.wakeLockTimeMs;
- totalWifiRunningTimeMs += sipper.wifiRunningTimeMs;
- totalBluetoothRunningTimeMs += sipper.bluetoothRunningTimeMs;
- totalGpsTimeMs += sipper.gpsTimeMs;
- totalCameraTimeMs += sipper.cameraTimeMs;
- totalFlashlightTimeMs += sipper.flashlightTimeMs;
- totalAudioTimeMs += sipper.audioTimeMs;
- totalVideoTimeMs += sipper.videoTimeMs;
- }
-
- BatteryConsumer requestedBatteryConsumer = null;
-
- for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
- if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
- requestedBatteryConsumer = consumer;
- }
- }
-
- double totalModeledCpuPowerMah = 0;
- BatteryConsumer requestedBatteryConsumerPowerProfileModeled = null;
- for (BatteryConsumer consumer : powerProfileModeledUsageStats.getUidBatteryConsumers()) {
- if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
- requestedBatteryConsumerPowerProfileModeled = consumer;
- }
-
- totalModeledCpuPowerMah += consumer.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_CPU);
- }
-
- if (requestedBatterySipper == null) {
+ if (requestedBatteryConsumer == null || requestedModeledBatteryConsumer == null) {
mBatteryConsumerInfo = null;
return;
}
- if (requestedBatteryConsumer == null) {
- for (BatteryConsumer consumer : batteryUsageStats.getSystemBatteryConsumers()) {
- if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
- requestedBatteryConsumer = consumer;
- break;
- }
- }
- }
-
mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
- context.getPackageManager(), requestedBatterySipper);
- long totalScreenMeasuredChargeUC =
- batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
- long uidScreenMeasuredChargeUC =
- requestedBatterySipper.uidObj.getScreenOnMeasuredBatteryConsumptionUC();
+ context.getPackageManager(), requestedBatteryConsumer);
- addEntry("Total power", EntryType.POWER,
- requestedBatterySipper.totalSmearedPowerMah, totalSmearedPowerMah);
- maybeAddMeasuredEnergyEntry(requestedBatterySipper.drainType, batteryStats);
+ double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];
+ double[] totalModeledPowerByComponentMah =
+ new double[BatteryConsumer.POWER_COMPONENT_COUNT];
+ long[] totalDurationByComponentMs = new long[BatteryConsumer.TIME_COMPONENT_COUNT];
+ final int customComponentCount =
+ requestedBatteryConsumer.getCustomPowerComponentCount();
+ double[] totalCustomPowerByComponentMah = new double[customComponentCount];
- addEntry("... excluding system", EntryType.POWER,
- requestedBatterySipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
- addEntry("Screen, smeared", EntryType.POWER,
- requestedBatterySipper.screenPowerMah, totalScreenPower);
- if (uidScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE
- && totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
- final double measuredCharge = UC_2_MAH * uidScreenMeasuredChargeUC;
- final double totalMeasuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC;
- addEntry("Screen, measured", EntryType.POWER,
- measuredCharge, totalMeasuredCharge);
- }
- addEntry("Other, smeared", EntryType.POWER,
- requestedBatterySipper.proportionalSmearMah, totalProportionalSmearMah);
- addEntry("Excluding smeared", EntryType.POWER,
- requestedBatterySipper.totalPowerMah, totalPowerMah);
- if (requestedBatteryConsumer != null) {
- addEntry("CPU", EntryType.POWER,
- requestedBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU),
- totalCpuPowerMah);
- if (requestedBatteryConsumerPowerProfileModeled != null) {
- addEntry("CPU (modeled)", EntryType.POWER,
- requestedBatteryConsumerPowerProfileModeled.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_CPU),
- totalModeledCpuPowerMah);
- }
- } else {
- addEntry("CPU (sipper)", EntryType.POWER,
- requestedBatterySipper.cpuPowerMah, totalCpuPowerMah);
- }
- addEntry("System services", EntryType.POWER,
- requestedBatterySipper.systemServiceCpuPowerMah, totalSystemServiceCpuPowerMah);
- if (requestedBatteryConsumer != null) {
- addEntry("Usage", EntryType.POWER,
- requestedBatteryConsumer.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_USAGE), totalUsagePowerMah);
- } else {
- addEntry("Usage (sipper)", EntryType.POWER,
- requestedBatterySipper.usagePowerMah, totalUsagePowerMah);
- }
- addEntry("Wake lock", EntryType.POWER,
- requestedBatterySipper.wakeLockPowerMah, totalWakeLockPowerMah);
- addEntry("Mobile radio", EntryType.POWER,
- requestedBatterySipper.mobileRadioPowerMah, totalMobileRadioPowerMah);
- addEntry("WiFi", EntryType.POWER,
- requestedBatterySipper.wifiPowerMah, totalWifiPowerMah);
- addEntry("Bluetooth", EntryType.POWER,
- requestedBatterySipper.bluetoothPowerMah, totalBluetoothPowerMah);
- addEntry("GPS", EntryType.POWER,
- requestedBatterySipper.gpsPowerMah, totalGpsPowerMah);
- addEntry("Camera", EntryType.POWER,
- requestedBatterySipper.cameraPowerMah, totalCameraPowerMah);
- addEntry("Flashlight", EntryType.POWER,
- requestedBatterySipper.flashlightPowerMah, totalFlashlightPowerMah);
- addEntry("Sensors", EntryType.POWER,
- requestedBatterySipper.sensorPowerMah, totalSensorPowerMah);
- addEntry("Audio", EntryType.POWER,
- requestedBatterySipper.audioPowerMah, totalAudioPowerMah);
- addEntry("Video", EntryType.POWER,
- requestedBatterySipper.videoPowerMah, totalVideoPowerMah);
+ computeTotalPower(batteryUsageStats, totalPowerByComponentMah);
+ computeTotalPower(modeledBatteryUsageStats, totalModeledPowerByComponentMah);
+ computeTotalPowerForCustomComponent(batteryUsageStats, totalCustomPowerByComponentMah);
+ computeTotalDuration(batteryUsageStats, totalDurationByComponentMs);
- addEntry("CPU time", EntryType.DURATION,
- requestedBatterySipper.cpuTimeMs, totalCpuTimeMs);
- addEntry("CPU foreground time", EntryType.DURATION,
- requestedBatterySipper.cpuFgTimeMs, totalCpuFgTimeMs);
- addEntry("Wake lock time", EntryType.DURATION,
- requestedBatterySipper.wakeLockTimeMs, totalWakeLockTimeMs);
- addEntry("WiFi running time", EntryType.DURATION,
- requestedBatterySipper.wifiRunningTimeMs, totalWifiRunningTimeMs);
- addEntry("Bluetooth time", EntryType.DURATION,
- requestedBatterySipper.bluetoothRunningTimeMs, totalBluetoothRunningTimeMs);
- addEntry("GPS time", EntryType.DURATION,
- requestedBatterySipper.gpsTimeMs, totalGpsTimeMs);
- addEntry("Camera time", EntryType.DURATION,
- requestedBatterySipper.cameraTimeMs, totalCameraTimeMs);
- addEntry("Flashlight time", EntryType.DURATION,
- requestedBatterySipper.flashlightTimeMs, totalFlashlightTimeMs);
- addEntry("Audio time", EntryType.DURATION,
- requestedBatterySipper.audioTimeMs, totalAudioTimeMs);
- addEntry("Video time", EntryType.DURATION,
- requestedBatterySipper.videoTimeMs, totalVideoTimeMs);
- }
-
- private boolean isSystemSipper(BatterySipper sipper) {
- final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
- if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
- return true;
- } else if (sipper.mPackages != null) {
- for (final String packageName : sipper.mPackages) {
- for (final String systemPackage : PACKAGES_SYSTEM) {
- if (systemPackage.equals(packageName)) {
- return true;
- }
- }
+ for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
+ final String metricTitle = getPowerMetricTitle(component);
+ final int powerModel = requestedBatteryConsumer.getPowerModel(component);
+ if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+ addEntry(metricTitle, EntryType.POWER_MODELED,
+ requestedBatteryConsumer.getConsumedPower(component),
+ totalPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
+ } else {
+ addEntry(metricTitle + " (measured)", EntryType.POWER_MEASURED,
+ requestedBatteryConsumer.getConsumedPower(component),
+ totalPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
+ addEntry(metricTitle + " (modeled)", EntryType.POWER_MODELED,
+ requestedModeledBatteryConsumer.getConsumedPower(component),
+ totalModeledPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
}
}
- return false;
+ for (int component = 0; component < customComponentCount; component++) {
+ final String name = requestedBatteryConsumer.getCustomPowerComponentName(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
+ addEntry(name + " (custom)", EntryType.POWER_CUSTOM,
+ requestedBatteryConsumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component),
+ totalCustomPowerByComponentMah[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
+ }
+
+ for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
+ final String metricTitle = getTimeMetricTitle(component);
+ addEntry(metricTitle, EntryType.DURATION,
+ requestedBatteryConsumer.getUsageDurationMillis(component),
+ totalDurationByComponentMs[component],
+ mBatteryConsumerInfo.isSystemBatteryConsumer);
+ }
}
- private void addEntry(String title, EntryType entryType, double amount, double totalAmount) {
+ private BatteryConsumer getRequestedBatteryConsumer(BatteryUsageStats batteryUsageStats,
+ String batteryConsumerId) {
+ for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
+ return consumer;
+ }
+ }
+ for (BatteryConsumer consumer : batteryUsageStats.getSystemBatteryConsumers()) {
+ if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
+ return consumer;
+ }
+ }
+ return null;
+ }
+
+ static String getPowerMetricTitle(int componentId) {
+ final String componentName = DebugUtils.constantToString(BatteryConsumer.class,
+ "POWER_COMPONENT_", componentId);
+ return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ')
+ + " power";
+ }
+
+ static String getTimeMetricTitle(int componentId) {
+ final String componentName = DebugUtils.constantToString(BatteryConsumer.class,
+ "TIME_COMPONENT_", componentId);
+ return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ')
+ + " time";
+ }
+
+ private void computeTotalPower(BatteryUsageStats batteryUsageStats,
+ double[] powerByComponentMah) {
+ for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT;
+ component++) {
+ powerByComponentMah[component] += consumer.getConsumedPower(component);
+ }
+ }
+ }
+
+ private void computeTotalDuration(BatteryUsageStats batteryUsageStats,
+ long[] durationByComponentMs) {
+ for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT;
+ component++) {
+ durationByComponentMs[component] += consumer.getUsageDurationMillis(component);
+ }
+ }
+ }
+
+ private void computeTotalPowerForCustomComponent(
+ BatteryUsageStats batteryUsageStats, double[] powerByComponentMah) {
+ for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ final int customComponentCount = consumer.getCustomPowerComponentCount();
+ for (int component = 0;
+ component < Math.min(customComponentCount, powerByComponentMah.length);
+ component++) {
+ powerByComponentMah[component] += consumer.getConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
+ }
+ }
+ }
+
+ private void addEntry(String title, EntryType entryType, double amount, double totalAmount,
+ boolean isSystemBatteryConsumer) {
Entry entry = new Entry();
entry.title = title;
entry.entryType = entryType;
entry.value = amount;
entry.total = totalAmount;
+ entry.isSystemBatteryConsumer = isSystemBatteryConsumer;
mEntries.add(entry);
}
- private void maybeAddMeasuredEnergyEntry(BatterySipper.DrainType drainType,
- BatteryStats batteryStats) {
- switch (drainType) {
- case AMBIENT_DISPLAY:
- final long totalDozeMeasuredChargeUC =
- batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
- if (totalDozeMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
- final double measuredCharge = UC_2_MAH * totalDozeMeasuredChargeUC;
- addEntry("Measured ambient display power", EntryType.POWER, measuredCharge,
- measuredCharge);
- }
- break;
- case SCREEN:
- final long totalScreenMeasuredChargeUC =
- batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
- if (totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
- final double measuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC;
- addEntry("Measured screen power", EntryType.POWER, measuredCharge,
- measuredCharge);
- }
- break;
- }
- }
-
public BatteryConsumerInfoHelper.BatteryConsumerInfo getBatteryConsumerInfo() {
return mBatteryConsumerInfo;
}
@@ -322,13 +198,9 @@
return mEntries;
}
- public static String batteryConsumerId(BatterySipper sipper) {
- return sipper.drainType + "|" + sipper.userId + "|" + sipper.getUid();
- }
-
public static String batteryConsumerId(BatteryConsumer consumer) {
if (consumer instanceof UidBatteryConsumer) {
- return BatterySipper.DrainType.APP + "|"
+ return "APP|"
+ UserHandle.getUserId(((UidBatteryConsumer) consumer).getUid()) + "|"
+ ((UidBatteryConsumer) consumer).getUid();
} else if (consumer instanceof SystemBatteryConsumer) {
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
index 8ee6c604..6288e0b 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
@@ -18,14 +18,14 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.os.BatteryConsumer;
import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.util.DebugUtils;
import androidx.annotation.NonNull;
-import com.android.internal.os.BatterySipper;
-
-import java.util.Locale;
-
class BatteryConsumerInfoHelper {
private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
@@ -37,111 +37,79 @@
public ApplicationInfo iconInfo;
public CharSequence packages;
public CharSequence details;
+ public boolean isSystemBatteryConsumer;
}
@NonNull
public static BatteryConsumerInfo makeBatteryConsumerInfo(PackageManager packageManager,
- @NonNull BatterySipper sipper) {
+ @NonNull BatteryConsumer batteryConsumer) {
BatteryConsumerInfo info = new BatteryConsumerInfo();
- info.id = BatteryConsumerData.batteryConsumerId(sipper);
- sipper.sumPower();
- info.powerMah = sipper.totalSmearedPowerMah;
- switch (sipper.drainType) {
- case APP: {
- int uid = sipper.getUid();
- info.details = String.format("UID: %d", uid);
- String packageWithHighestDrain = sipper.packageWithHighestDrain;
- if (uid == Process.ROOT_UID) {
- info.label = "<root>";
- } else {
- String[] packages = packageManager.getPackagesForUid(uid);
- String primaryPackageName = null;
- if (uid == Process.SYSTEM_UID) {
- primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
- } else if (packages != null) {
- for (String name : packages) {
- primaryPackageName = name;
- if (name.equals(packageWithHighestDrain)) {
- break;
- }
- }
- }
+ info.id = BatteryConsumerData.batteryConsumerId(batteryConsumer);
+ info.powerMah = batteryConsumer.getConsumedPower();
- if (primaryPackageName != null) {
- try {
- ApplicationInfo applicationInfo =
- packageManager.getApplicationInfo(primaryPackageName, 0);
- info.label = applicationInfo.loadLabel(packageManager);
- info.iconInfo = applicationInfo;
- } catch (PackageManager.NameNotFoundException e) {
- info.label = primaryPackageName;
+ if (batteryConsumer instanceof UidBatteryConsumer) {
+ final UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
+ int uid = uidBatteryConsumer.getUid();
+ info.details = String.format("UID: %d", uid);
+ String packageWithHighestDrain = uidBatteryConsumer.getPackageWithHighestDrain();
+ if (uid == Process.ROOT_UID) {
+ info.label = "<root>";
+ } else {
+ String[] packages = packageManager.getPackagesForUid(uid);
+ String primaryPackageName = null;
+ if (uid == Process.SYSTEM_UID) {
+ primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
+ } else if (packages != null) {
+ for (String name : packages) {
+ primaryPackageName = name;
+ if (name.equals(packageWithHighestDrain)) {
+ break;
}
- } else if (packageWithHighestDrain != null) {
- info.label = packageWithHighestDrain;
- }
-
- if (packages != null && packages.length > 0) {
- StringBuilder sb = new StringBuilder();
- if (primaryPackageName != null) {
- sb.append(primaryPackageName);
- }
- for (String packageName : packages) {
- if (packageName.equals(primaryPackageName)) {
- continue;
- }
-
- if (sb.length() != 0) {
- sb.append(", ");
- }
- sb.append(packageName);
- }
-
- info.packages = sb;
}
}
- break;
+
+ if (primaryPackageName != null) {
+ try {
+ ApplicationInfo applicationInfo =
+ packageManager.getApplicationInfo(primaryPackageName, 0);
+ info.label = applicationInfo.loadLabel(packageManager);
+ info.iconInfo = applicationInfo;
+ } catch (PackageManager.NameNotFoundException e) {
+ info.label = primaryPackageName;
+ }
+ } else if (packageWithHighestDrain != null) {
+ info.label = packageWithHighestDrain;
+ }
+
+ if (packages != null && packages.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ if (primaryPackageName != null) {
+ sb.append(primaryPackageName);
+ }
+ for (String packageName : packages) {
+ if (packageName.equals(primaryPackageName)) {
+ continue;
+ }
+
+ if (sb.length() != 0) {
+ sb.append(", ");
+ }
+ sb.append(packageName);
+ }
+
+ info.packages = sb;
+ }
}
- case USER:
- info.label = "User";
- info.details = String.format(Locale.getDefault(), "User ID: %d", sipper.userId);
- break;
- case AMBIENT_DISPLAY:
- info.label = "Ambient display";
- break;
- case BLUETOOTH:
- info.label = "Bluetooth";
- break;
- case CAMERA:
- info.label = "Camera";
- break;
- case CELL:
- info.label = "Cell";
- break;
- case FLASHLIGHT:
- info.label = "Flashlight";
- break;
- case IDLE:
- info.label = "Idle";
- break;
- case MEMORY:
- info.label = "Memory";
- break;
- case OVERCOUNTED:
- info.label = "Overcounted";
- break;
- case PHONE:
- info.label = "Phone";
- break;
- case SCREEN:
- info.label = "Screen";
- break;
- case UNACCOUNTED:
- info.label = "Unaccounted";
- break;
- case WIFI:
- info.label = "WiFi";
- break;
+ } else if (batteryConsumer instanceof SystemBatteryConsumer) {
+ final SystemBatteryConsumer systemBatteryConsumer =
+ (SystemBatteryConsumer) batteryConsumer;
+ final int drainType = systemBatteryConsumer.getDrainType();
+ String name = DebugUtils.constantToString(SystemBatteryConsumer.class, "DRAIN_TYPE_",
+ drainType);
+ info.label = name.charAt(0) + name.substring(1).toLowerCase().replace('_', ' ');
+ info.isSystemBatteryConsumer = true;
}
+
// Default the app icon to System Server. This includes root, dex2oat and other UIDs.
if (info.iconInfo == null) {
try {
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java
index bb11fd5..4922087 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerFragment.java
@@ -18,10 +18,11 @@
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.BatteryStats;
+import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,8 +38,6 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.frameworks.core.batterystatsviewer.BatteryConsumerInfoHelper.BatteryConsumerInfo;
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.ArrayList;
@@ -99,44 +98,39 @@
private static class BatteryConsumerListLoader extends
AsyncLoaderCompat<List<BatteryConsumerInfo>> {
- private final BatteryStatsHelper mStatsHelper;
private final int mPickerType;
- private final UserManager mUserManager;
+ private final BatteryStatsManager mBatteryStatsManager;
private final PackageManager mPackageManager;
BatteryConsumerListLoader(Context context, int pickerType) {
super(context);
- mUserManager = context.getSystemService(UserManager.class);
- mStatsHelper = new BatteryStatsHelper(context, false /* collectBatteryBroadcast */);
+ mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class);
mPickerType = pickerType;
- mStatsHelper.create((Bundle) null);
- mStatsHelper.clearStats();
mPackageManager = context.getPackageManager();
}
@Override
public List<BatteryConsumerInfo> loadInBackground() {
+ final BatteryUsageStats batteryUsageStats = mBatteryStatsManager.getBatteryUsageStats();
+
List<BatteryConsumerInfo> batteryConsumerList = new ArrayList<>();
-
- mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
-
- final List<BatterySipper> usageList = mStatsHelper.getUsageList();
- for (BatterySipper sipper : usageList) {
- switch (mPickerType) {
- case PICKER_TYPE_APP:
- if (sipper.drainType != BatterySipper.DrainType.APP) {
- continue;
- }
- break;
- case PICKER_TYPE_DRAIN:
- default:
- if (sipper.drainType == BatterySipper.DrainType.APP) {
- continue;
- }
- }
-
- batteryConsumerList.add(
- BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager, sipper));
+ switch (mPickerType) {
+ case PICKER_TYPE_APP:
+ for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+ batteryConsumerList.add(
+ BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager,
+ consumer));
+ }
+ break;
+ case PICKER_TYPE_DRAIN:
+ default:
+ for (SystemBatteryConsumer consumer :
+ batteryUsageStats.getSystemBatteryConsumers()) {
+ batteryConsumerList.add(
+ BatteryConsumerInfoHelper.makeBatteryConsumerInfo(mPackageManager,
+ consumer));
+ }
+ break;
}
batteryConsumerList.sort(
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
index 4ead8ee..74d3fb3 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
@@ -18,13 +18,10 @@
import android.content.Context;
import android.content.SharedPreferences;
-import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -41,7 +38,6 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.Collections;
@@ -50,24 +46,24 @@
public class BatteryStatsViewerActivity extends ComponentActivity {
private static final int BATTERY_STATS_REFRESH_RATE_MILLIS = 60 * 1000;
- public static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId";
- public static final int LOADER_BATTERY_STATS_HELPER = 0;
- public static final int LOADER_BATTERY_USAGE_STATS = 1;
+ private static final int MILLIS_IN_MINUTE = 60000;
+ private static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId";
+ private static final int LOADER_BATTERY_USAGE_STATS = 1;
private BatteryStatsDataAdapter mBatteryStatsDataAdapter;
- private Runnable mBatteryStatsRefresh = this::periodicBatteryStatsRefresh;
+ private final Runnable mBatteryStatsRefresh = this::periodicBatteryStatsRefresh;
private SharedPreferences mSharedPref;
private String mBatteryConsumerId;
private TextView mTitleView;
private TextView mDetailsView;
private ImageView mIconView;
private TextView mPackagesView;
+ private View mHeadingsView;
private RecyclerView mBatteryConsumerDataView;
private View mLoadingView;
private View mEmptyView;
- private ActivityResultLauncher<Void> mStartAppPicker = registerForActivityResult(
+ private final ActivityResultLauncher<Void> mStartAppPicker = registerForActivityResult(
BatteryConsumerPickerActivity.CONTRACT, this::onApplicationSelected);
- private BatteryStatsHelper mBatteryStatsHelper;
private List<BatteryUsageStats> mBatteryUsageStats;
@Override
@@ -85,6 +81,7 @@
mDetailsView = findViewById(R.id.details);
mIconView = findViewById(android.R.id.icon);
mPackagesView = findViewById(R.id.packages);
+ mHeadingsView = findViewById(R.id.headings);
mBatteryConsumerDataView = findViewById(R.id.battery_consumer_data_view);
mBatteryConsumerDataView.setLayoutManager(new LinearLayoutManager(this));
@@ -139,55 +136,10 @@
private void loadBatteryStats() {
LoaderManager loaderManager = LoaderManager.getInstance(this);
- loaderManager.restartLoader(LOADER_BATTERY_STATS_HELPER, null,
- new BatteryStatsHelperLoaderCallbacks());
loaderManager.restartLoader(LOADER_BATTERY_USAGE_STATS, null,
new BatteryUsageStatsLoaderCallbacks());
}
- private static class BatteryStatsHelperLoader extends AsyncLoaderCompat<BatteryStatsHelper> {
- private final BatteryStatsHelper mBatteryStatsHelper;
- private final UserManager mUserManager;
-
- BatteryStatsHelperLoader(Context context) {
- super(context);
- mUserManager = context.getSystemService(UserManager.class);
- mBatteryStatsHelper = new BatteryStatsHelper(context,
- false /* collectBatteryBroadcast */);
- mBatteryStatsHelper.create((Bundle) null);
- mBatteryStatsHelper.clearStats();
- }
-
- @Override
- public BatteryStatsHelper loadInBackground() {
- mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
- UserHandle.myUserId());
- return mBatteryStatsHelper;
- }
-
- @Override
- protected void onDiscardResult(BatteryStatsHelper result) {
- }
- }
-
- private class BatteryStatsHelperLoaderCallbacks implements LoaderCallbacks<BatteryStatsHelper> {
- @NonNull
- @Override
- public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
- return new BatteryStatsHelperLoader(BatteryStatsViewerActivity.this);
- }
-
- @Override
- public void onLoadFinished(@NonNull Loader<BatteryStatsHelper> loader,
- BatteryStatsHelper batteryStatsHelper) {
- onBatteryStatsHelperLoaded(batteryStatsHelper);
- }
-
- @Override
- public void onLoaderReset(@NonNull Loader<BatteryStatsHelper> loader) {
- }
- }
-
private static class BatteryUsageStatsLoader extends
AsyncLoaderCompat<List<BatteryUsageStats>> {
private final BatteryStatsManager mBatteryStatsManager;
@@ -200,10 +152,13 @@
@Override
public List<BatteryUsageStats> loadInBackground() {
final BatteryUsageStatsQuery queryDefault =
- new BatteryUsageStatsQuery.Builder().build();
+ new BatteryUsageStatsQuery.Builder()
+ .includePowerModels()
+ .build();
final BatteryUsageStatsQuery queryPowerProfileModeledOnly =
new BatteryUsageStatsQuery.Builder()
.powerProfileModeledOnly()
+ .includePowerModels()
.build();
return mBatteryStatsManager.getBatteryUsageStats(
List.of(queryDefault, queryPowerProfileModeledOnly));
@@ -233,22 +188,13 @@
}
}
- public void onBatteryStatsHelperLoaded(BatteryStatsHelper batteryStatsHelper) {
- mBatteryStatsHelper = batteryStatsHelper;
- onBatteryStatsDataLoaded();
- }
-
private void onBatteryUsageStatsLoaded(List<BatteryUsageStats> batteryUsageStats) {
mBatteryUsageStats = batteryUsageStats;
onBatteryStatsDataLoaded();
}
public void onBatteryStatsDataLoaded() {
- if (mBatteryStatsHelper == null || mBatteryUsageStats == null) {
- return;
- }
-
- BatteryConsumerData batteryConsumerData = new BatteryConsumerData(this, mBatteryStatsHelper,
+ BatteryConsumerData batteryConsumerData = new BatteryConsumerData(this,
mBatteryUsageStats, mBatteryConsumerId);
BatteryConsumerInfoHelper.BatteryConsumerInfo
@@ -256,6 +202,7 @@
if (batteryConsumerInfo == null) {
mTitleView.setText("Battery consumer not found");
mPackagesView.setVisibility(View.GONE);
+ mHeadingsView.setVisibility(View.GONE);
} else {
mTitleView.setText(batteryConsumerInfo.label);
if (batteryConsumerInfo.details != null) {
@@ -273,6 +220,12 @@
} else {
mPackagesView.setVisibility(View.GONE);
}
+
+ if (batteryConsumerInfo.isSystemBatteryConsumer) {
+ mHeadingsView.setVisibility(View.VISIBLE);
+ } else {
+ mHeadingsView.setVisibility(View.GONE);
+ }
}
mBatteryStatsDataAdapter.setEntries(batteryConsumerData.getEntries());
@@ -290,6 +243,7 @@
private static class BatteryStatsDataAdapter extends
RecyclerView.Adapter<BatteryStatsDataAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder {
+ public ImageView iconImageView;
public TextView titleTextView;
public TextView amountTextView;
public TextView percentTextView;
@@ -297,6 +251,7 @@
ViewHolder(View itemView) {
super(itemView);
+ iconImageView = itemView.findViewById(R.id.icon);
titleTextView = itemView.findViewById(R.id.title);
amountTextView = itemView.findViewById(R.id.amount);
percentTextView = itemView.findViewById(R.id.percent);
@@ -328,21 +283,56 @@
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
BatteryConsumerData.Entry entry = mEntries.get(position);
switch (entry.entryType) {
- case POWER:
+ case POWER_MODELED:
viewHolder.titleTextView.setText(entry.title);
viewHolder.amountTextView.setText(
String.format(Locale.getDefault(), "%.1f mAh", entry.value));
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_calculate_24);
+ viewHolder.itemView.setBackgroundResource(
+ R.color.battery_consumer_bg_power_profile);
+ break;
+ case POWER_MEASURED:
+ viewHolder.titleTextView.setText(entry.title);
+ viewHolder.amountTextView.setText(
+ String.format(Locale.getDefault(), "%.1f mAh", entry.value));
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_amp_24);
+ viewHolder.itemView.setBackgroundResource(
+ R.color.battery_consumer_bg_measured_energy);
+ break;
+ case POWER_CUSTOM:
+ viewHolder.titleTextView.setText(entry.title);
+ viewHolder.amountTextView.setText(
+ String.format(Locale.getDefault(), "%.1f mAh", entry.value));
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_custom_24);
+ viewHolder.itemView.setBackgroundResource(
+ R.color.battery_consumer_bg_measured_energy);
break;
case DURATION:
viewHolder.titleTextView.setText(entry.title);
- viewHolder.amountTextView.setText(
- String.format(Locale.getDefault(), "%,d ms", (long) entry.value));
+ final long durationMs = (long) entry.value;
+ CharSequence text;
+ if (durationMs < MILLIS_IN_MINUTE) {
+ text = String.format(Locale.getDefault(), "%,d ms", durationMs);
+ } else {
+ text = String.format(Locale.getDefault(), "%,d m %d s",
+ durationMs / MILLIS_IN_MINUTE,
+ (durationMs % MILLIS_IN_MINUTE) / 1000);
+ }
+
+ viewHolder.amountTextView.setText(text);
+ viewHolder.iconImageView.setImageResource(R.drawable.gm_timer_24);
+ viewHolder.itemView.setBackground(null);
break;
}
- double proportion = entry.total != 0 ? entry.value * 100 / entry.total : 0;
- viewHolder.percentTextView.setText(String.format(Locale.getDefault(), "%.1f%%",
- proportion));
+ double proportion;
+ if (entry.isSystemBatteryConsumer) {
+ proportion = entry.value != 0 ? entry.total * 100 / entry.value : 0;
+ } else {
+ proportion = entry.total != 0 ? entry.value * 100 / entry.total : 0;
+ }
+ viewHolder.percentTextView.setText(
+ String.format(Locale.getDefault(), "%.1f%%", proportion));
}
}
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index e5da41c..2e2e6bd 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -86,7 +86,6 @@
@RunWith(AndroidJUnit4.class)
@MediumTest
@Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
public class ActivityThreadTest {
private static final int TIMEOUT_SEC = 10;
@@ -352,8 +351,9 @@
final Rect bounds = activity.getWindowManager().getCurrentWindowMetrics().getBounds();
assertEquals(activityConfigPortrait.windowConfiguration.getBounds(), bounds);
- // Ensure that Activity#onConfigurationChanged() is only called once.
- assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+ // Ensure that Activity#onConfigurationChanged() not be called because the changes in
+ // WindowConfiguration shouldn't be reported.
+ assertEquals(numOfConfig, activity.mNumOfConfigChanges);
}
@Test
@@ -379,7 +379,7 @@
Configuration config = new Configuration();
config.seq = BASE_SEQ + 1;
- config.smallestScreenWidthDp = 100;
+ config.orientation = ORIENTATION_LANDSCAPE;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
// Wait until the main thread is performing the configuration change for the configuration
@@ -389,17 +389,17 @@
config = new Configuration();
config.seq = BASE_SEQ + 2;
- config.smallestScreenWidthDp = 200;
+ config.orientation = ORIENTATION_PORTRAIT;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
config = new Configuration();
config.seq = BASE_SEQ + 3;
- config.smallestScreenWidthDp = 300;
+ config.orientation = ORIENTATION_LANDSCAPE;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
config = new Configuration();
config.seq = BASE_SEQ + 4;
- config.smallestScreenWidthDp = 400;
+ config.orientation = ORIENTATION_PORTRAIT;
appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
activity.mConfigLatch.countDown();
@@ -411,7 +411,7 @@
// Only two more configuration changes: one with seq BASE_SEQ + 1; another with seq
// BASE_SEQ + 4. Configurations scheduled in between should be dropped.
assertEquals(numOfConfig + 2, activity.mNumOfConfigChanges);
- assertEquals(400, activity.mConfig.smallestScreenWidthDp);
+ assertEquals(ORIENTATION_PORTRAIT, activity.mConfig.orientation);
}
@Test
@@ -515,6 +515,7 @@
}
@Test
+ @FlakyTest(bugId = 176134235)
public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index fb0dd46..b2b9ab3 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -93,8 +93,8 @@
@Test
public void testComputeForPassword_metrics() {
- final PasswordMetrics metrics =
- PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes());
+ final PasswordMetrics metrics = PasswordMetrics.computeForPasswordOrPin(
+ "6B~0z1Z3*8A".getBytes(), /* isPin */ false);
assertEquals(11, metrics.length);
assertEquals(4, metrics.letters);
assertEquals(3, metrics.upperCase);
@@ -133,61 +133,71 @@
@Test
public void testDetermineComplexity_lowNumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("1234".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("1234".getBytes(),
+ /* isPin */true).determineComplexity());
}
@Test
public void testDetermineComplexity_lowNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("124".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("124".getBytes(),
+ /* isPin */ true).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("a!".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("a!".getBytes(),
+ /* isPin */ false).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("a!1".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("a!1".getBytes(),
+ /* isPin */ false).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("1238".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("1238".getBytes(),
+ /* isPin */ true).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("ab!c".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("ab!c".getBytes(),
+ /* isPin */ false).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("ab!1".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("ab!1".getBytes(),
+ /* isPin */ false).determineComplexity());
}
@Test
public void testDetermineComplexity_highNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("12389647!".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("12389647!".getBytes(),
+ /* isPin */ true).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("alphabetic!".getBytes()).determineComplexity());
+ PasswordMetrics.computeForPasswordOrPin("alphabetic!".getBytes(),
+ /* isPin */ false).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphanumeric() {
- assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword(
- "alphanumeric123!".getBytes()).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_HIGH,
+ PasswordMetrics.computeForPasswordOrPin("alphanumeric123!".getBytes(),
+ /* isPin */ false).determineComplexity());
}
@Test
diff --git a/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java b/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
index e951054..f1be173 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
@@ -28,6 +28,7 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static org.junit.Assert.assertEquals;
@@ -80,7 +81,7 @@
public void testGetMinMetrics_numeric() {
PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC);
PasswordMetrics minMetrics = policy.getMinMetrics();
- assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+ assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType);
assertEquals(TEST_VALUE, minMetrics.length);
assertEquals(0, minMetrics.numeric); // numeric can doesn't really require digits.
assertEquals(0, minMetrics.letters);
@@ -104,7 +105,7 @@
public void testGetMinMetrics_numericComplex() {
PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC_COMPLEX);
PasswordMetrics minMetrics = policy.getMinMetrics();
- assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+ assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType);
assertEquals(TEST_VALUE, minMetrics.length);
assertEquals(0, minMetrics.numeric);
assertEquals(0, minMetrics.letters);
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
index 56c685a..3d18337 100644
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/AppSearchSessionUnitTest.java
@@ -20,6 +20,7 @@
import static org.testng.Assert.expectThrows;
+import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
@@ -89,8 +90,12 @@
});
// Verify the NullPointException has been thrown.
- ExecutionException executionException = expectThrows(ExecutionException.class,
- putDocumentsFuture::get);
- assertThat(executionException.getCause()).isInstanceOf(NullPointerException.class);
+ ExecutionException executionException =
+ expectThrows(ExecutionException.class, putDocumentsFuture::get);
+ assertThat(executionException.getCause()).isInstanceOf(AppSearchException.class);
+ AppSearchException appSearchException = (AppSearchException) executionException.getCause();
+ assertThat(appSearchException.getResultCode())
+ .isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
+ assertThat(appSearchException.getMessage()).startsWith("NullPointerException");
}
}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
new file mode 100644
index 0000000..de0670b
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import org.junit.Test;
+
+public class AppSearchResultTest {
+ @Test
+ public void testMapNullPointerException() {
+ NullPointerException e =
+ expectThrows(
+ NullPointerException.class,
+ () -> {
+ Object o = null;
+ o.toString();
+ });
+ AppSearchResult<?> result = AppSearchResult.throwableToFailedResult(e);
+ assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
+ // Makes sure the exception name is included in the string. Some exceptions have terse or
+ // missing strings so it's confusing to read the output without the exception name.
+ assertThat(result.getErrorMessage()).startsWith("NullPointerException");
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
index 22c71b52..e7b88c8 100644
--- a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
+++ b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
@@ -32,6 +32,7 @@
import android.graphics.Rect;
import android.os.Handler;
import android.os.ICancellationSignal;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -189,4 +190,15 @@
verifyNoMoreInteractions(mRemote);
}
+ @Test
+ public void testClose_whileActive() throws RemoteException {
+ mConnection.startCapture(mSurface, mRemote);
+
+ mCallback.completeStartRequest();
+ assertTrue(mConnection.isActive());
+
+ mConnection.close();
+ mCallback.completeEndRequest();
+ assertFalse(mConnection.isActive());
+ }
}
diff --git a/core/tests/coretests/src/android/window/WindowContextTest.java b/core/tests/coretests/src/android/window/WindowContextTest.java
index 614e7c1..83280f1 100644
--- a/core/tests/coretests/src/android/window/WindowContextTest.java
+++ b/core/tests/coretests/src/android/window/WindowContextTest.java
@@ -17,6 +17,7 @@
package android.window;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -209,6 +210,38 @@
mWms.removeWindowToken(existingToken, DEFAULT_DISPLAY);
}
+ @Test
+ public void testWindowContextAddViewWithSubWindowType_NotCrash() throws Throwable {
+ final WindowContext windowContext = createWindowContext(TYPE_INPUT_METHOD);
+ final WindowManager wm = windowContext.getSystemService(WindowManager.class);
+
+ // Create a WindowToken with system window type.
+ final IBinder existingToken = new Binder();
+ mWms.addWindowToken(existingToken, TYPE_INPUT_METHOD, windowContext.getDisplayId(),
+ null /* options */);
+
+ final WindowManager.LayoutParams params =
+ new WindowManager.LayoutParams(TYPE_INPUT_METHOD);
+ params.token = existingToken;
+ final View parentWindow = new View(windowContext);
+
+ final AttachStateListener listener = new AttachStateListener();
+ parentWindow.addOnAttachStateChangeListener(listener);
+
+ // Add the parent window
+ mInstrumentation.runOnMainSync(() -> wm.addView(parentWindow, params));
+
+ assertTrue(listener.mLatch.await(4, TimeUnit.SECONDS));
+
+ final WindowManager.LayoutParams subWindowAttrs =
+ new WindowManager.LayoutParams(TYPE_APPLICATION_ATTACHED_DIALOG);
+ subWindowAttrs.token = parentWindow.getWindowToken();
+ final View subWindow = new View(windowContext);
+
+ // Add a window with sub-window type.
+ mInstrumentation.runOnMainSync(() -> wm.addView(subWindow, subWindowAttrs));
+ }
+
private WindowContext createWindowContext() {
return createWindowContext(TYPE_APPLICATION_OVERLAY);
}
@@ -219,4 +252,16 @@
.getDisplay(DEFAULT_DISPLAY);
return (WindowContext) instContext.createWindowContext(display, type, null /* options */);
}
+
+ private static class AttachStateListener implements View.OnAttachStateChangeListener {
+ final CountDownLatch mLatch = new CountDownLatch(1);
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {}
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
index cf47efd..c63ec45 100644
--- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
@@ -65,12 +65,12 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(90 * MINUTE_IN_MS);
// 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(27.777778);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
}
@@ -91,11 +91,11 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(90 * MINUTE_IN_MS);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(15.0);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 1e614c4..3a6f7b8 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -109,11 +109,11 @@
}
/** Call only after setting the power profile information. */
- public BatteryUsageStatsRule initMeasuredEnergyStatsLocked(int numCustom) {
+ public BatteryUsageStatsRule initMeasuredEnergyStatsLocked() {
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
Arrays.fill(supportedStandardBuckets, true);
- mBatteryStats.initMeasuredEnergyStatsLocked(supportedStandardBuckets, numCustom);
+ mBatteryStats.initMeasuredEnergyStatsLocked(supportedStandardBuckets, new String[0]);
mBatteryStats.informThatAllExternalStatsAreFlushed();
return this;
}
@@ -167,15 +167,11 @@
}
BatteryUsageStats apply(BatteryUsageStatsQuery query, PowerCalculator... calculators) {
- final long[] customMeasuredEnergiesMicroJoules =
- mBatteryStats.getCustomConsumerMeasuredBatteryConsumptionUC();
- final int customMeasuredEnergiesCount = customMeasuredEnergiesMicroJoules != null
- ? customMeasuredEnergiesMicroJoules.length
- : 0;
+ final String[] customPowerComponentNames = mBatteryStats.getCustomPowerComponentNames();
final boolean includePowerModels = (query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
- customMeasuredEnergiesCount, 0, includePowerModels);
+ customPowerComponentNames, 0, includePowerModels);
SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
for (int i = 0; i < uidStats.size(); i++) {
builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 60df968..b253599 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -66,17 +66,18 @@
final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
- final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1)
- .setDischargePercentage(20)
- .setDischargedPowerRange(1000, 2000)
- .setStatsStartTimestamp(1000);
+ final BatteryUsageStats.Builder builder =
+ new BatteryUsageStats.Builder(new String[]{"FOO"}, 1)
+ .setDischargePercentage(20)
+ .setDischargedPowerRange(1000, 2000)
+ .setStatsStartTimestamp(1000);
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid)
.setPackageWithHighestDrain("foo")
.setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000)
.setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, 2000)
.setConsumedPower(
- BatteryConsumer.POWER_COMPONENT_USAGE, 300)
+ BatteryConsumer.POWER_COMPONENT_SCREEN, 300)
.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_CPU, 400)
.setConsumedPowerForCustomComponent(
@@ -122,7 +123,7 @@
assertThat(uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_BACKGROUND)).isEqualTo(2000);
assertThat(uidBatteryConsumer.getConsumedPower(
- BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
+ BatteryConsumer.POWER_COMPONENT_SCREEN)).isEqualTo(300);
assertThat(uidBatteryConsumer.getConsumedPower(
BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(400);
assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent(
@@ -134,6 +135,9 @@
assertThat(uidBatteryConsumer.getUsageDurationForCustomComponentMillis(
BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(800);
assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(1200);
+ assertThat(uidBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
+ assertThat(uidBatteryConsumer.getCustomPowerComponentName(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
} else {
fail("Unexpected UID " + uidBatteryConsumer.getUid());
}
@@ -153,6 +157,11 @@
BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(10400);
assertThat(systemBatteryConsumer.getConsumedPower()).isEqualTo(20300);
assertThat(systemBatteryConsumer.getPowerConsumedByApps()).isEqualTo(20000);
+ assertThat(systemBatteryConsumer.getUsageDurationMillis())
+ .isEqualTo(10400); // max
+ assertThat(systemBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
+ assertThat(systemBatteryConsumer.getCustomPowerComponentName(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
} else {
fail("Unexpected drain type " + systemBatteryConsumer.getDrainType());
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
index f65fb95..bf87683 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
@@ -16,6 +16,8 @@
package com.android.internal.os;
+import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -23,16 +25,21 @@
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
+import android.util.proto.ProtoOutputStream;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.BinderInternal.CallSession;
import com.android.internal.os.BinderLatencyObserver.LatencyDims;
+import com.android.internal.os.BinderLatencyProto.ApiStats;
+import com.android.internal.os.BinderLatencyProto.Dims;
+import com.android.internal.os.BinderLatencyProto.RepeatedApiStats;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
@@ -49,11 +56,17 @@
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
+ blo.setElapsedTime(4);
blo.callEnded(callSession);
+ blo.setElapsedTime(6);
blo.callEnded(callSession);
callSession.transactionCode = 2;
+ blo.setElapsedTime(8);
blo.callEnded(callSession);
+ blo.setElapsedTime(10);
blo.callEnded(callSession);
ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms();
@@ -74,8 +87,10 @@
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
callSession.transactionCode = 2;
+ blo.setElapsedTime(4);
blo.callEnded(callSession);
ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms();
@@ -89,13 +104,13 @@
@Test
public void testTooCallLengthOverflow() {
TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
- blo.setElapsedTime(2L + (long) Integer.MAX_VALUE);
blo.setHistogramBucketsParams(5, 5, 1.125f);
Binder binder = new Binder();
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+ blo.setElapsedTime(2L + (long) Integer.MAX_VALUE);
blo.callEnded(callSession);
// The long call should be capped to maxint (to not overflow) and placed in the last bucket.
@@ -114,6 +129,7 @@
CallSession callSession = new CallSession();
callSession.binderClass = binder.getClass();
callSession.transactionCode = 1;
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
LatencyDims dims = new LatencyDims(binder.getClass(), 1);
@@ -122,14 +138,111 @@
assertThat(blo.getLatencyHistograms().get(dims))
.asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
// Try to add another sample.
+ blo.setElapsedTime(2);
blo.callEnded(callSession);
// Make sure the buckets don't overflow.
assertThat(blo.getLatencyHistograms().get(dims))
.asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
}
+ @Test
+ public void testSingleAtomPush() {
+ TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
+
+ Binder binder = new Binder();
+ CallSession callSession = new CallSession();
+ callSession.binderClass = binder.getClass();
+ callSession.transactionCode = 1;
+ blo.setElapsedTime(7);
+ blo.callEnded(callSession);
+ blo.callEnded(callSession);
+ blo.setElapsedTime(8);
+ blo.callEnded(callSession);
+
+ // Trigger the statsd push.
+ blo.getStatsdPushRunnable().run();
+
+ ProtoOutputStream expectedProto = new ProtoOutputStream();
+ long apiStatsToken = expectedProto.start(RepeatedApiStats.API_STATS);
+ long dimsToken = expectedProto.start(ApiStats.DIMS);
+ expectedProto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto.write(Dims.SERVICE_METHOD_NAME, "1");
+ expectedProto.end(dimsToken);
+ expectedProto.write(ApiStats.FIRST_BUCKET_INDEX, 3);
+ expectedProto.write(ApiStats.BUCKETS, 2);
+ expectedProto.write(ApiStats.BUCKETS, 1);
+ expectedProto.end(apiStatsToken);
+
+ assertThat(blo.getWrittenAtoms())
+ .containsExactly(Arrays.toString(expectedProto.getBytes()));
+ }
+
+ @Test
+ public void testMultipleAtomPush() {
+ TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
+
+ BinderTransactionNameResolver resolver = new BinderTransactionNameResolver();
+
+
+ Binder binder = new Binder();
+ CallSession callSession = new CallSession();
+ callSession.binderClass = binder.getClass();
+ callSession.transactionCode = 1;
+ blo.setElapsedTime(1);
+ blo.callEnded(callSession);
+ callSession.transactionCode = 2;
+ blo.setElapsedTime(5);
+ blo.callEnded(callSession);
+ callSession.transactionCode = 3;
+ blo.callEnded(callSession);
+
+ // Trigger the statsd push.
+ blo.getStatsdPushRunnable().run();
+
+ ProtoOutputStream expectedProto1 = new ProtoOutputStream();
+ long apiStatsToken = expectedProto1.start(RepeatedApiStats.API_STATS);
+ long dimsToken = expectedProto1.start(ApiStats.DIMS);
+ expectedProto1.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto1.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto1.write(Dims.SERVICE_METHOD_NAME, "1");
+ expectedProto1.end(dimsToken);
+ expectedProto1.write(ApiStats.FIRST_BUCKET_INDEX, 0);
+ expectedProto1.write(ApiStats.BUCKETS, 1);
+ expectedProto1.end(apiStatsToken);
+
+ apiStatsToken = expectedProto1.start(RepeatedApiStats.API_STATS);
+ dimsToken = expectedProto1.start(ApiStats.DIMS);
+ expectedProto1.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto1.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto1.write(Dims.SERVICE_METHOD_NAME, "2");
+ expectedProto1.end(dimsToken);
+ expectedProto1.write(ApiStats.FIRST_BUCKET_INDEX, 1);
+ expectedProto1.write(ApiStats.BUCKETS, 1);
+ expectedProto1.end(apiStatsToken);
+
+ ProtoOutputStream expectedProto2 = new ProtoOutputStream();
+ apiStatsToken = expectedProto2.start(RepeatedApiStats.API_STATS);
+ dimsToken = expectedProto2.start(ApiStats.DIMS);
+ expectedProto2.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+ expectedProto2.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+ expectedProto2.write(Dims.SERVICE_METHOD_NAME, "3");
+ expectedProto2.end(dimsToken);
+ expectedProto2.write(ApiStats.FIRST_BUCKET_INDEX, 1);
+ expectedProto2.write(ApiStats.BUCKETS, 1);
+ expectedProto2.end(apiStatsToken);
+
+ // Each ApiStats is around ~60 bytes so only two should fit in an atom.
+ assertThat(blo.getWrittenAtoms())
+ .containsExactly(
+ Arrays.toString(expectedProto1.getBytes()),
+ Arrays.toString(expectedProto2.getBytes()))
+ .inOrder();
+ }
+
public static class TestBinderLatencyObserver extends BinderLatencyObserver {
private long mElapsedTime = 0;
+ private ArrayList<String> mWrittenAtoms;
TestBinderLatencyObserver() {
// Make random generator not random.
@@ -145,16 +258,30 @@
}
});
setSamplingInterval(1);
+ mWrittenAtoms = new ArrayList<>();
}
@Override
protected long getElapsedRealtimeMicro() {
- mElapsedTime += 2;
return mElapsedTime;
}
+ @Override
+ protected int getMaxAtomSizeBytes() {
+ return 1100;
+ }
+
+ @Override
+ protected void writeAtomToStatsd(ProtoOutputStream atom) {
+ mWrittenAtoms.add(Arrays.toString(atom.getBytes()));
+ }
+
public void setElapsedTime(long time) {
mElapsedTime = time;
}
+
+ public ArrayList<String> getWrittenAtoms() {
+ return mWrittenAtoms;
+ }
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 1a87c10..71cdb5f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -44,7 +44,7 @@
.setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE, 10.0)
.setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX, 50.0)
.setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0)
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
@Test
public void testTimerBasedModel() {
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index 31abbc2..63af21d 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -96,7 +96,7 @@
.setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader)
.setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader)
.setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
- .initMeasuredEnergyStatsLocked(supportedPowerBuckets, 0);
+ .initMeasuredEnergyStatsLocked(supportedPowerBuckets, new String[0]);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
index 95c3b4e..aa066c3 100644
--- a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
@@ -42,7 +42,7 @@
.setAveragePower(PowerProfile.POWER_GPS_ON, 360.0)
.setAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED,
new double[] {720.0, 1440.0, 1800.0})
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
@Test
public void testTimerBasedModel() {
diff --git a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
index 781e725..a9800b7 100644
--- a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
@@ -48,9 +48,9 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_IDLE);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_IDLE))
.isEqualTo(3000);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_IDLE))
.isWithin(PRECISION).of(0.7);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
index 8f21503..71dbcdb 100644
--- a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
@@ -55,9 +55,9 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MEMORY);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MEMORY))
.isEqualTo(3000);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MEMORY))
.isWithin(PRECISION).of(0.7);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index 3505e8c..5b84a1b 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -57,7 +57,7 @@
.setAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX, 1440.0)
.setAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX,
new double[] {720.0, 1080.0, 1440.0, 1800.0, 2160.0})
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
@Test
public void testCounterBasedModel() {
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 26adbe9..7a7d9f5 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -51,7 +51,9 @@
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
Arrays.fill(supportedStandardBuckets, true);
- mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedStandardBuckets, 2);
+ final String[] customBucketNames = {"FOO", "BAR"};
+ mGlobalMeasuredEnergyStats =
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
// A no-op handler.
mHandler = new Handler(Looper.getMainLooper()) {
diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
index 9cd6ea8..7d829e4 100644
--- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
@@ -84,13 +84,13 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(80 * MINUTE_IN_MS);
// 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s) = 166.66666 mAh
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(166.66666);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
assertThat(consumer.getConsumedPower())
.isWithin(PRECISION).of(166.66666);
@@ -153,11 +153,11 @@
SystemBatteryConsumer consumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
- assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
.isEqualTo(80 * MINUTE_IN_MS);
- assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isWithin(PRECISION).of(92.0);
- assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+ assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
assertThat(consumer.getConsumedPower())
.isWithin(PRECISION).of(92.0);
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index 2e501db..9349bce 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -53,7 +53,7 @@
.setAveragePower(PowerProfile.POWER_WIFI_SCAN, 480.0)
.setAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, 720.0)
.setAveragePower(PowerProfile.POWER_WIFI_ACTIVE, 1080.0)
- .initMeasuredEnergyStatsLocked(0);
+ .initMeasuredEnergyStatsLocked();
/** Sets up a batterystats object with pre-populated network values. */
private BatteryStatsImpl setupTestNetworkNumbers() {
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
index ed6e27b..f1edc87 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -23,6 +23,8 @@
import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON;
import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_OTHER;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -49,13 +51,13 @@
@Test
public void testConstruction() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
if (supportedStandardBuckets[i]) {
@@ -66,21 +68,22 @@
assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(0L, stats.getAccumulatedCustomBucketCharge(i));
}
+ assertThat(stats.getCustomBucketNames()).asList().containsExactly("A", "B");
}
@Test
public void testCreateFromTemplate() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -99,7 +102,7 @@
newStats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(i));
}
}
@@ -107,13 +110,13 @@
@Test
public void testReadWriteParcel() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -130,25 +133,25 @@
assertEquals(stats.getAccumulatedStandardBucketCharge(i),
newStats.getAccumulatedStandardBucketCharge(i));
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(stats.getAccumulatedCustomBucketCharge(i),
newStats.getAccumulatedCustomBucketCharge(i));
}
assertEquals(POWER_DATA_UNAVAILABLE,
- newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
+ newStats.getAccumulatedCustomBucketCharge(customBucketNames.length + 1));
parcel.recycle();
}
@Test
public void testCreateAndReadSummaryFromParcel() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -166,25 +169,25 @@
assertEquals(stats.getAccumulatedStandardBucketCharge(i),
newStats.getAccumulatedStandardBucketCharge(i));
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(stats.getAccumulatedCustomBucketCharge(i),
newStats.getAccumulatedCustomBucketCharge(i));
}
assertEquals(POWER_DATA_UNAVAILABLE,
- newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
+ newStats.getAccumulatedCustomBucketCharge(customBucketNames.length + 1));
parcel.recycle();
}
@Test
public void testCreateAndReadSummaryFromParcel_existingTemplate() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats template =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -205,7 +208,7 @@
newsupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true
newsupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false
final MeasuredEnergyStats newTemplate =
- new MeasuredEnergyStats(newsupportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(newsupportedStandardBuckets, customBucketNames);
parcel.setDataPosition(0);
final MeasuredEnergyStats newStats =
@@ -225,23 +228,23 @@
newStats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(stats.getAccumulatedCustomBucketCharge(i),
newStats.getAccumulatedCustomBucketCharge(i));
}
assertEquals(POWER_DATA_UNAVAILABLE,
- newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1));
+ newStats.getAccumulatedCustomBucketCharge(customBucketNames.length + 1));
parcel.recycle();
}
@Test
public void testCreateAndReadSummaryFromParcel_skipZero() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
Arrays.fill(supportedStandardBuckets, true);
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
// Accumulate charge in one bucket and one custom bucket, the rest should be zero
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 200);
stats.updateCustomBucket(1, 60);
@@ -298,13 +301,13 @@
@Test
public void testCreateAndReadSummaryFromParcel_nullTemplate() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -324,13 +327,13 @@
@Test
public void testCreateAndReadSummaryFromParcel_boring() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats template =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -348,7 +351,7 @@
newSupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true
newSupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false
final MeasuredEnergyStats newTemplate =
- new MeasuredEnergyStats(newSupportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(newSupportedStandardBuckets, customBucketNames);
parcel.setDataPosition(0);
final MeasuredEnergyStats newStats =
@@ -362,13 +365,13 @@
@Test
public void testUpdateBucket() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_DOZE, 30);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -389,7 +392,8 @@
@Test
public void testIsValidCustomBucket() {
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3);
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS],
+ new String[]{"A", "B", "C"});
assertFalse(stats.isValidCustomBucket(-1));
assertTrue(stats.isValidCustomBucket(0));
assertTrue(stats.isValidCustomBucket(1));
@@ -398,7 +402,7 @@
assertFalse(stats.isValidCustomBucket(4));
final MeasuredEnergyStats boringStats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0);
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[0]);
assertFalse(boringStats.isValidCustomBucket(-1));
assertFalse(boringStats.isValidCustomBucket(0));
assertFalse(boringStats.isValidCustomBucket(1));
@@ -407,8 +411,8 @@
@Test
public void testGetAccumulatedCustomBucketCharges() {
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3);
-
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS],
+ new String[]{"A", "B", "C"});
stats.updateCustomBucket(0, 50);
stats.updateCustomBucket(1, 60);
stats.updateCustomBucket(2, 13);
@@ -425,7 +429,7 @@
@Test
public void testGetAccumulatedCustomBucketCharges_empty() {
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0);
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[0]);
final long[] output = stats.getAccumulatedCustomBucketCharges();
assertEquals(0, output.length);
@@ -433,22 +437,23 @@
@Test
public void testGetNumberCustomChargeBuckets() {
- assertEquals(0, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0)
- .getNumberCustomPowerBuckets());
- assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3)
- .getNumberCustomPowerBuckets());
+ assertEquals(0,
+ new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], new String[0])
+ .getNumberCustomPowerBuckets());
+ assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS],
+ new String[]{"A", "B", "C"}).getNumberCustomPowerBuckets());
}
@Test
public void testReset() {
final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
- final int numCustomBuckets = 2;
+ final String[] customBucketNames = {"A", "B"};
supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true;
supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
final MeasuredEnergyStats stats =
- new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
+ new MeasuredEnergyStats(supportedStandardBuckets, customBucketNames);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
@@ -466,7 +471,7 @@
assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i));
}
}
- for (int i = 0; i < numCustomBuckets; i++) {
+ for (int i = 0; i < customBucketNames.length; i++) {
assertEquals(0, stats.getAccumulatedCustomBucketCharge(i));
}
diff --git a/core/tests/coretests/src/com/android/internal/view/ScrollCaptureViewSupportTest.java b/core/tests/coretests/src/com/android/internal/view/ScrollCaptureViewSupportTest.java
new file mode 100644
index 0000000..cb72b2d
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/view/ScrollCaptureViewSupportTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.view;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+
+public class ScrollCaptureViewSupportTest {
+
+ ScrollCaptureViewHelper<View> mViewHelper = new ScrollCaptureViewHelper<View>() {
+ @Override
+ public void onPrepareForStart(@NonNull View view, @NonNull Rect scrollBounds) {
+ }
+
+ @NonNull
+ @Override
+ public ScrollResult onScrollRequested(@NonNull View view, @NonNull Rect scrollBounds,
+ @NonNull Rect requestRect) {
+ return new ScrollResult();
+ }
+
+ @Override
+ public void onPrepareForEnd(@NonNull View view) {
+ }
+ };
+
+
+ /**
+ * Test scroll bounds are computed correctly. onComputeScrollBounds is currently a
+ * default interface method of ScrollCaptureViewHelper.
+ */
+ @Test
+ public void testComputeScrollBounds() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+
+ ViewGroup target = new ViewGroup(context) {
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ // n/a
+ }
+ };
+
+ target.setPadding(25, 50, 25, 50);
+ target.setLeftTopRightBottom(0, 0, 200, 200);
+
+
+ // clipToPadding == false: No effect
+ target.setClipToPadding(false);
+ Rect scrollBounds = mViewHelper.onComputeScrollBounds(target);
+ assertEquals("Computed scroll bounds are incorrect with clipToPadding=false",
+ new Rect(0, 0, 200, 200), scrollBounds);
+
+ // clipToPadding == true: Inset by padding
+ target.setClipToPadding(true);
+ scrollBounds = mViewHelper.onComputeScrollBounds(target);
+ assertEquals("Computed scroll bounds are incorrect with clipToPadding=true",
+ new Rect(25, 50, 175, 150), scrollBounds);
+ }
+
+}
diff --git a/core/tests/nfctests/Android.bp b/core/tests/nfctests/Android.bp
new file mode 100644
index 0000000..335cea1
--- /dev/null
+++ b/core/tests/nfctests/Android.bp
@@ -0,0 +1,38 @@
+// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "NfcManagerTests",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ ],
+ libs: [
+ "android.test.runner",
+ ],
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/nfctests/AndroidManifest.xml b/core/tests/nfctests/AndroidManifest.xml
new file mode 100644
index 0000000..99e2c34c
--- /dev/null
+++ b/core/tests/nfctests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.nfc">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- This is a self-instrumenting test package. -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.nfc"
+ android:label="NFC Manager Tests">
+ </instrumentation>
+
+</manifest>
+
diff --git a/core/tests/nfctests/AndroidTest.xml b/core/tests/nfctests/AndroidTest.xml
new file mode 100644
index 0000000..490d6f5
--- /dev/null
+++ b/core/tests/nfctests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for NFC Manager test cases">
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-suite-tag" value="apct-instrumentation"/>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="NfcManagerTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="NfcManagerTests"/>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.nfc" />
+ <option name="hidden-api-checks" value="false"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/core/tests/nfctests/OWNERS b/core/tests/nfctests/OWNERS
new file mode 100644
index 0000000..34b095c
--- /dev/null
+++ b/core/tests/nfctests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/nfc/OWNERS
diff --git a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java b/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
new file mode 100644
index 0000000..43f9b6f
--- /dev/null
+++ b/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.nfc;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
+import android.os.RemoteException;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Test of {@link NfcControllerAlwaysOnListener}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NfcControllerAlwaysOnListenerTest {
+
+ private INfcAdapter mNfcAdapter = mock(INfcAdapter.class);
+
+ private Throwable mThrowRemoteException = new RemoteException("RemoteException");
+
+ private static Executor getExecutor() {
+ return new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ command.run();
+ }
+ };
+ }
+
+ private static void verifyListenerInvoked(ControllerAlwaysOnListener listener) {
+ verify(listener, times(1)).onControllerAlwaysOnChanged(anyBoolean());
+ }
+
+ @Test
+ public void testRegister_RegisterUnregister() throws RemoteException {
+ NfcControllerAlwaysOnListener mListener =
+ new NfcControllerAlwaysOnListener(mNfcAdapter);
+ ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class);
+ ControllerAlwaysOnListener mockListener2 = mock(ControllerAlwaysOnListener.class);
+
+ // Verify that the state listener registered with the NFC Adapter
+ mListener.register(getExecutor(), mockListener1);
+ verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
+
+ // Register a second client and no new call to NFC Adapter
+ mListener.register(getExecutor(), mockListener2);
+ verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
+
+ // Unregister first listener
+ mListener.unregister(mockListener1);
+ verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
+ verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any());
+
+ // Unregister second listener and the state listener registered with the NFC Adapter
+ mListener.unregister(mockListener2);
+ verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
+ verify(mNfcAdapter, times(1)).unregisterControllerAlwaysOnListener(any());
+ }
+
+ @Test
+ public void testRegister_FirstRegisterFails() throws RemoteException {
+ NfcControllerAlwaysOnListener mListener =
+ new NfcControllerAlwaysOnListener(mNfcAdapter);
+ ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class);
+ ControllerAlwaysOnListener mockListener2 = mock(ControllerAlwaysOnListener.class);
+
+ // Throw a remote exception whenever first registering
+ doThrow(mThrowRemoteException).when(mNfcAdapter).registerControllerAlwaysOnListener(
+ any());
+
+ mListener.register(getExecutor(), mockListener1);
+ verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
+
+ // No longer throw an exception, instead succeed
+ doNothing().when(mNfcAdapter).registerControllerAlwaysOnListener(any());
+
+ // Register a different listener
+ mListener.register(getExecutor(), mockListener2);
+ verify(mNfcAdapter, times(2)).registerControllerAlwaysOnListener(any());
+
+ // Ensure first and second listener were invoked
+ mListener.onControllerAlwaysOnChanged(true);
+ verifyListenerInvoked(mockListener1);
+ verifyListenerInvoked(mockListener2);
+ }
+
+ @Test
+ public void testRegister_RegisterSameListenerTwice() throws RemoteException {
+ NfcControllerAlwaysOnListener mListener =
+ new NfcControllerAlwaysOnListener(mNfcAdapter);
+ ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class);
+
+ // Register the same listener Twice
+ mListener.register(getExecutor(), mockListener);
+ mListener.register(getExecutor(), mockListener);
+ verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
+
+ // Invoke a state change and ensure the listener is only called once
+ mListener.onControllerAlwaysOnChanged(true);
+ verifyListenerInvoked(mockListener);
+ }
+
+ @Test
+ public void testNotify_AllListenersNotified() throws RemoteException {
+
+ NfcControllerAlwaysOnListener listener = new NfcControllerAlwaysOnListener(mNfcAdapter);
+ List<ControllerAlwaysOnListener> mockListeners = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class);
+ listener.register(getExecutor(), mockListener);
+ mockListeners.add(mockListener);
+ }
+
+ // Invoke a state change and ensure all listeners are invoked
+ listener.onControllerAlwaysOnChanged(true);
+ for (ControllerAlwaysOnListener mListener : mockListeners) {
+ verifyListenerInvoked(mListener);
+ }
+ }
+
+ @Test
+ public void testStateChange_CorrectValue() {
+ runStateChangeValue(true, true);
+ runStateChangeValue(false, false);
+
+ }
+
+ private void runStateChangeValue(boolean isEnabledIn, boolean isEnabledOut) {
+ NfcControllerAlwaysOnListener listener = new NfcControllerAlwaysOnListener(mNfcAdapter);
+ ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class);
+ listener.register(getExecutor(), mockListener);
+ listener.onControllerAlwaysOnChanged(isEnabledIn);
+ verify(mockListener, times(1)).onControllerAlwaysOnChanged(isEnabledOut);
+ verify(mockListener, times(0)).onControllerAlwaysOnChanged(!isEnabledOut);
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2fe8b28..5f34426 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -348,6 +348,8 @@
<permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
<permission name="android.permission.INSTALL_PACKAGES"/>
<!-- Needed for test only -->
+ <permission name="android.permission.ACCESS_MTP"/>
+ <!-- Needed for test only -->
<permission name="android.permission.INTERACT_ACROSS_PROFILES"/>
<!-- Permission required to test onPermissionsChangedListener -->
<permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
@@ -404,6 +406,7 @@
<permission name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" />
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
+ <permission name="android.permission.UWB_PRIVILEGED"/>
<permission name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index fec78f0..81f1021 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1825,6 +1825,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
},
+ "35398067": {
+ "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+ "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+ },
"38267433": {
"message": "Attempted to reset replacing window on non-existing app token %s",
"level": "WARN",
diff --git a/errorprone/java/android/annotation/SuppressLint.java b/errorprone/java/android/annotation/SuppressLint.java
new file mode 100644
index 0000000..2d3456b
--- /dev/null
+++ b/errorprone/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ /**
+ * The set of warnings (identified by the lint issue id) that should be
+ * ignored by lint. It is not an error to specify an unrecognized name.
+ */
+ String[] value();
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
new file mode 100644
index 0000000..3b5a58c
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
@@ -0,0 +1,328 @@
+/*
+ * 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.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Matchers.allOf;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.enclosingClass;
+import static com.google.errorprone.matchers.Matchers.instanceMethod;
+import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
+import static com.google.errorprone.matchers.Matchers.methodInvocation;
+import static com.google.errorprone.matchers.Matchers.methodIsNamed;
+import static com.google.errorprone.matchers.Matchers.staticMethod;
+
+import android.annotation.SuppressLint;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.google.errorprone.util.ASTHelpers;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.util.TreeScanner;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.ClassType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ * Inspects both the client and server side of AIDL interfaces to ensure that
+ * any {@code RequiresPermission} annotations are consistently declared and
+ * enforced.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkRequiresPermission",
+ summary = "Verifies that @RequiresPermission annotations are consistent across AIDL",
+ severity = WARNING)
+public final class RequiresPermissionChecker extends BugChecker implements MethodTreeMatcher {
+ private static final String ANNOTATION_REQUIRES_PERMISSION = "RequiresPermission";
+
+ private static final Matcher<ExpressionTree> ENFORCE_VIA_CONTEXT = methodInvocation(
+ instanceMethod()
+ .onDescendantOf("android.content.Context")
+ .withNameMatching(
+ Pattern.compile("^(enforce|check)(Calling)?(OrSelf)?Permission$")));
+ private static final Matcher<ExpressionTree> ENFORCE_VIA_CHECKER = methodInvocation(
+ staticMethod()
+ .onClass("android.content.PermissionChecker")
+ .withNameMatching(Pattern.compile("^check.*")));
+
+ private static final Matcher<MethodTree> BINDER_INTERNALS = allOf(
+ enclosingClass(isSubtypeOf("android.os.IInterface")),
+ anyOf(
+ methodIsNamed("onTransact"),
+ methodIsNamed("dump"),
+ enclosingClass(simpleNameMatches(Pattern.compile("^(Stub|Default|Proxy)$")))));
+ private static final Matcher<MethodTree> LOCAL_INTERNALS = anyOf(
+ methodIsNamed("finalize"),
+ allOf(
+ enclosingClass(isSubtypeOf("android.content.BroadcastReceiver")),
+ methodIsNamed("onReceive")),
+ allOf(
+ enclosingClass(isSubtypeOf("android.database.ContentObserver")),
+ methodIsNamed("onChange")),
+ allOf(
+ enclosingClass(isSubtypeOf("android.os.Handler")),
+ methodIsNamed("handleMessage")),
+ allOf(
+ enclosingClass(isSubtypeOf("android.os.IBinder.DeathRecipient")),
+ methodIsNamed("binderDied")));
+
+ private static final Matcher<ExpressionTree> CLEAR_CALL = methodInvocation(staticMethod()
+ .onClass("android.os.Binder").withSignature("clearCallingIdentity()"));
+ private static final Matcher<ExpressionTree> RESTORE_CALL = methodInvocation(staticMethod()
+ .onClass("android.os.Binder").withSignature("restoreCallingIdentity(long)"));
+
+ @Override
+ public Description matchMethod(MethodTree tree, VisitorState state) {
+ // Ignore methods without an implementation
+ if (tree.getBody() == null) return Description.NO_MATCH;
+
+ // Ignore certain types of Binder generated code
+ if (BINDER_INTERNALS.matches(tree, state)) return Description.NO_MATCH;
+
+ // Ignore known-local methods which don't need to propagate
+ if (LOCAL_INTERNALS.matches(tree, state)) return Description.NO_MATCH;
+
+ // Ignore when suppressed via superclass
+ final MethodSymbol method = ASTHelpers.getSymbol(tree);
+ if (isSuppressedRecursively(method, state)) return Description.NO_MATCH;
+
+ // First, look at all outgoing method invocations to ensure that we
+ // carry those annotations forward; yell if we're too narrow
+ final ParsedRequiresPermission expectedPerm = parseRequiresPermissionRecursively(
+ method, state);
+ final ParsedRequiresPermission actualPerm = new ParsedRequiresPermission();
+ final Description desc = tree.accept(new TreeScanner<Description, Void>() {
+ private boolean clearedCallingIdentity = false;
+
+ @Override
+ public Description visitMethodInvocation(MethodInvocationTree node, Void param) {
+ if (CLEAR_CALL.matches(node, state)) {
+ clearedCallingIdentity = true;
+ } else if (RESTORE_CALL.matches(node, state)) {
+ clearedCallingIdentity = false;
+ } else if (!clearedCallingIdentity) {
+ final ParsedRequiresPermission nodePerm = parseRequiresPermissionRecursively(
+ node, state);
+ if (!expectedPerm.containsAll(nodePerm)) {
+ return buildDescription(node).setMessage("Annotated " + expectedPerm
+ + " but too narrow; invokes method requiring " + nodePerm).build();
+ } else {
+ actualPerm.addAll(nodePerm);
+ }
+ }
+ return super.visitMethodInvocation(node, param);
+ }
+
+ @Override
+ public Description reduce(Description r1, Description r2) {
+ return (r1 != null) ? r1 : r2;
+ }
+ }, null);
+ if (desc != null) return desc;
+
+ // Second, determine if we actually used all permissions that we claim
+ // to require; yell if we're too broad
+ if (!actualPerm.containsAll(expectedPerm)) {
+ return buildDescription(tree).setMessage("Annotated " + expectedPerm
+ + " but too wide; only invokes methods requiring " + actualPerm).build();
+ }
+
+ return Description.NO_MATCH;
+ }
+
+ static class ParsedRequiresPermission {
+ final Set<String> allOf = new HashSet<>();
+ final Set<String> anyOf = new HashSet<>();
+
+ public boolean isEmpty() {
+ return allOf.isEmpty() && anyOf.isEmpty();
+ }
+
+ /**
+ * Validate that this annotation effectively "contains" the given
+ * annotation. This is typically used to ensure that a method carries
+ * along all relevant annotations for the methods it invokes.
+ */
+ public boolean containsAll(ParsedRequiresPermission perm) {
+ boolean allMet = allOf.containsAll(perm.allOf);
+ boolean anyMet = false;
+ if (perm.anyOf.isEmpty()) {
+ anyMet = true;
+ } else {
+ for (String anyPerm : perm.anyOf) {
+ if (allOf.contains(anyPerm) || anyOf.contains(anyPerm)) {
+ anyMet = true;
+ }
+ }
+ }
+ return allMet && anyMet;
+ }
+
+ @Override
+ public String toString() {
+ if (isEmpty()) {
+ return "[none]";
+ }
+ String res = "{allOf=" + allOf;
+ if (!anyOf.isEmpty()) {
+ res += " anyOf=" + anyOf;
+ }
+ res += "}";
+ return res;
+ }
+
+ public void addAll(ParsedRequiresPermission perm) {
+ this.allOf.addAll(perm.allOf);
+ this.anyOf.addAll(perm.anyOf);
+ }
+
+ public void addAll(AnnotationMirror a) {
+ for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : a
+ .getElementValues().entrySet()) {
+ if (entry.getKey().getSimpleName().contentEquals("value")) {
+ maybeAdd(allOf, entry.getValue());
+ } else if (entry.getKey().getSimpleName().contentEquals("allOf")) {
+ maybeAdd(allOf, entry.getValue());
+ } else if (entry.getKey().getSimpleName().contentEquals("anyOf")) {
+ maybeAdd(anyOf, entry.getValue());
+ }
+ }
+ }
+
+ private static void maybeAdd(Set<String> set, Object value) {
+ if (value instanceof AnnotationValue) {
+ maybeAdd(set, ((AnnotationValue) value).getValue());
+ } else if (value instanceof String) {
+ set.add((String) value);
+ } else if (value instanceof Collection) {
+ for (Object o : (Collection) value) {
+ maybeAdd(set, o);
+ }
+ } else {
+ throw new RuntimeException(String.valueOf(value.getClass()));
+ }
+ }
+ }
+
+ private static ParsedRequiresPermission parseRequiresPermissionRecursively(
+ MethodInvocationTree tree, VisitorState state) {
+ if (ENFORCE_VIA_CONTEXT.matches(tree, state)) {
+ final ParsedRequiresPermission res = new ParsedRequiresPermission();
+ res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(0))));
+ return res;
+ } else if (ENFORCE_VIA_CHECKER.matches(tree, state)) {
+ final ParsedRequiresPermission res = new ParsedRequiresPermission();
+ res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(1))));
+ return res;
+ } else {
+ final MethodSymbol method = ASTHelpers.getSymbol(tree);
+ return parseRequiresPermissionRecursively(method, state);
+ }
+ }
+
+ /**
+ * Parse any {@code RequiresPermission} annotations associated with the
+ * given method, defined either directly on the method or by any superclass.
+ */
+ private static ParsedRequiresPermission parseRequiresPermissionRecursively(
+ MethodSymbol method, VisitorState state) {
+ final List<MethodSymbol> symbols = new ArrayList<>();
+ symbols.add(method);
+ symbols.addAll(ASTHelpers.findSuperMethods(method, state.getTypes()));
+
+ final ParsedRequiresPermission res = new ParsedRequiresPermission();
+ for (MethodSymbol symbol : symbols) {
+ for (AnnotationMirror a : symbol.getAnnotationMirrors()) {
+ if (a.getAnnotationType().asElement().getSimpleName()
+ .contentEquals(ANNOTATION_REQUIRES_PERMISSION)) {
+ res.addAll(a);
+ }
+ }
+ }
+ return res;
+ }
+
+ private boolean isSuppressedRecursively(MethodSymbol method, VisitorState state) {
+ // Is method suppressed anywhere?
+ if (isSuppressed(method)) return true;
+ for (MethodSymbol symbol : ASTHelpers.findSuperMethods(method, state.getTypes())) {
+ if (isSuppressed(symbol)) return true;
+ }
+
+ // Is class suppressed anywhere?
+ final ClassSymbol clazz = ASTHelpers.enclosingClass(method);
+ if (isSuppressed(clazz)) return true;
+ Type type = clazz.getSuperclass();
+ while (type != null) {
+ if (isSuppressed(type.tsym)) return true;
+ if (type instanceof ClassType) {
+ type = ((ClassType) type).supertype_field;
+ } else {
+ type = null;
+ }
+ }
+ return false;
+ }
+
+ public boolean isSuppressed(Symbol symbol) {
+ return isSuppressed(ASTHelpers.getAnnotation(symbol, SuppressWarnings.class))
+ || isSuppressed(ASTHelpers.getAnnotation(symbol, SuppressLint.class));
+ }
+
+ private boolean isSuppressed(SuppressWarnings anno) {
+ return (anno != null) && !Collections.disjoint(Arrays.asList(anno.value()), allNames());
+ }
+
+ private boolean isSuppressed(SuppressLint anno) {
+ return (anno != null) && !Collections.disjoint(Arrays.asList(anno.value()), allNames());
+ }
+
+ private static Matcher<ClassTree> simpleNameMatches(Pattern pattern) {
+ return new Matcher<ClassTree>() {
+ @Override
+ public boolean matches(ClassTree tree, VisitorState state) {
+ final CharSequence name = tree.getSimpleName().toString();
+ return pattern.matcher(name).matches();
+ }
+ };
+ }
+}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java
new file mode 100644
index 0000000..771258d
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.errorprone.CompilationTestHelper;
+import com.google.errorprone.bugpatterns.android.RequiresPermissionChecker.ParsedRequiresPermission;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(JUnit4.class)
+public class RequiresPermissionCheckerTest {
+ private CompilationTestHelper compilationHelper;
+
+ private static final String RED = "red";
+ private static final String BLUE = "blue";
+
+ @Before
+ public void setUp() {
+ compilationHelper = CompilationTestHelper.newInstance(
+ RequiresPermissionChecker.class, getClass());
+ }
+
+ private static ParsedRequiresPermission build(Collection<String> allOf,
+ Collection<String> anyOf) {
+ ParsedRequiresPermission res = new ParsedRequiresPermission();
+ res.allOf.addAll(allOf);
+ res.anyOf.addAll(anyOf);
+ return res;
+ }
+
+ @Test
+ public void testParser_AllOf() {
+ final ParsedRequiresPermission a = build(Arrays.asList(RED, BLUE), Arrays.asList());
+ final ParsedRequiresPermission b = build(Arrays.asList(RED), Arrays.asList());
+ assertTrue(a.containsAll(b));
+ assertFalse(b.containsAll(a));
+ }
+
+ @Test
+ public void testParser_AnyOf() {
+ final ParsedRequiresPermission a = build(Arrays.asList(), Arrays.asList(RED, BLUE));
+ final ParsedRequiresPermission b = build(Arrays.asList(), Arrays.asList(RED));
+ assertTrue(a.containsAll(b));
+ assertTrue(b.containsAll(a));
+ }
+
+ @Test
+ public void testParser_AnyOf_AllOf() {
+ final ParsedRequiresPermission a = build(Arrays.asList(RED, BLUE), Arrays.asList());
+ final ParsedRequiresPermission b = build(Arrays.asList(), Arrays.asList(RED));
+ assertTrue(a.containsAll(b));
+ assertFalse(b.containsAll(a));
+ }
+
+ @Test
+ public void testSimple() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.content.Context;",
+ "public abstract class ColorManager extends Context {",
+ " private static final String RED = \"red\";",
+ " private static final String BLUE = \"blue\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " @RequiresPermission(BLUE) abstract int blue();",
+ " @RequiresPermission(allOf={RED, BLUE}) abstract int all();",
+ " @RequiresPermission(anyOf={RED, BLUE}) abstract int any();",
+ " @RequiresPermission(allOf={RED, BLUE})",
+ " int redPlusBlue() { return red() + blue(); }",
+ " @RequiresPermission(allOf={RED, BLUE})",
+ " int allPlusRed() { return all() + red(); }",
+ " @RequiresPermission(allOf={RED})",
+ " int anyPlusRed() { return any() + red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testManager() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/foo/IColorService.java")
+ .addSourceFile("/android/os/IInterface.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.foo.IColorService;",
+ "public class ColorManager {",
+ " IColorService mService;",
+ " @RequiresPermission(IColorService.RED)",
+ " void redValid() {",
+ " mService.red();",
+ " }",
+ " @RequiresPermission(allOf={IColorService.RED, IColorService.BLUE})",
+ " // BUG: Diagnostic contains:",
+ " void redOverbroad() {",
+ " mService.red();",
+ " }",
+ " @RequiresPermission(IColorService.BLUE)",
+ " void redInvalid() {",
+ " // BUG: Diagnostic contains:",
+ " mService.red();",
+ " }",
+ " void redMissing() {",
+ " // BUG: Diagnostic contains:",
+ " mService.red();",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testService() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/foo/IColorService.java")
+ .addSourceFile("/android/os/IInterface.java")
+ .addSourceLines("ColorService.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.content.Context;",
+ "import android.foo.IColorService;",
+ "class ColorService extends Context implements IColorService {",
+ " public void none() {}",
+ " // BUG: Diagnostic contains:",
+ " public void red() {}",
+ " // BUG: Diagnostic contains:",
+ " public void redAndBlue() {}",
+ " // BUG: Diagnostic contains:",
+ " public void redOrBlue() {}",
+ " void onTransact(int code) {",
+ " red();",
+ " }",
+ "}",
+ "class ValidService extends ColorService {",
+ " public void red() {",
+ " ((Context) this).enforceCallingOrSelfPermission(RED, null);",
+ " }",
+ "}",
+ "class InvalidService extends ColorService {",
+ " public void red() {",
+ " // BUG: Diagnostic contains:",
+ " ((Context) this).enforceCallingOrSelfPermission(BLUE, null);",
+ " }",
+ "}",
+ "class NestedService extends ColorService {",
+ " public void red() {",
+ " enforceRed();",
+ " }",
+ " @RequiresPermission(RED)",
+ " public void enforceRed() {",
+ " ((Context) this).enforceCallingOrSelfPermission(RED, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testBroadcastReceiver() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/content/BroadcastReceiver.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.content.BroadcastReceiver;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public abstract class ColorManager extends BroadcastReceiver {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " // BUG: Diagnostic contains:",
+ " public void onSend() { red(); }",
+ " public void onReceive(Context context, Intent intent) { red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ @Ignore
+ public void testContentObserver() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/database/ContentObserver.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.database.ContentObserver;",
+ "public abstract class ColorManager {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " public void example() {",
+ " ContentObserver ob = new ContentObserver() {",
+ " public void onChange(boolean selfChange) {",
+ " red();",
+ " }",
+ " };",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testHandler() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/os/Handler.java")
+ .addSourceFile("/android/os/Message.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.os.Handler;",
+ "import android.os.Message;",
+ "public abstract class ColorManager extends Handler {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " // BUG: Diagnostic contains:",
+ " public void sendMessage() { red(); }",
+ " public void handleMessage(Message msg) { red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testDeathRecipient() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/os/IBinder.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.os.IBinder;",
+ "public abstract class ColorManager implements IBinder.DeathRecipient {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " // BUG: Diagnostic contains:",
+ " public void binderAlive() { red(); }",
+ " public void binderDied() { red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testClearCallingIdentity() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/os/Binder.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.os.Binder;",
+ "public abstract class ColorManager {",
+ " private static final String RED = \"red\";",
+ " private static final String BLUE = \"blue\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " @RequiresPermission(BLUE) abstract int blue();",
+ " @RequiresPermission(BLUE)",
+ " public void half() {",
+ " final long token = Binder.clearCallingIdentity();",
+ " try {",
+ " red();",
+ " } finally {",
+ " Binder.restoreCallingIdentity(token);",
+ " }",
+ " blue();",
+ " }",
+ " public void full() {",
+ " final long token = Binder.clearCallingIdentity();",
+ " red();",
+ " blue();",
+ " }",
+ " @RequiresPermission(allOf={RED, BLUE})",
+ " public void none() {",
+ " red();",
+ " blue();",
+ " final long token = Binder.clearCallingIdentity();",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testSuppressLint() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/annotation/SuppressLint.java")
+ .addSourceLines("Example.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.annotation.SuppressLint;",
+ "@SuppressLint(\"AndroidFrameworkRequiresPermission\")",
+ "abstract class Parent {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ "}",
+ "abstract class Child extends Parent {",
+ " private static final String BLUE = \"blue\";",
+ " @RequiresPermission(BLUE) abstract int blue();",
+ " public void toParent() { red(); }",
+ " public void toSibling() { blue(); }",
+ "}")
+ .doTest();
+ }
+}
diff --git a/errorprone/tests/res/android/annotation/RequiresPermission.java b/errorprone/tests/res/android/annotation/RequiresPermission.java
new file mode 100644
index 0000000..670eb3b
--- /dev/null
+++ b/errorprone/tests/res/android/annotation/RequiresPermission.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
+public @interface RequiresPermission {
+ String value() default "";
+ String[] allOf() default {};
+ String[] anyOf() default {};
+}
diff --git a/errorprone/tests/res/android/annotation/SuppressLint.java b/errorprone/tests/res/android/annotation/SuppressLint.java
new file mode 100644
index 0000000..4150c47
--- /dev/null
+++ b/errorprone/tests/res/android/annotation/SuppressLint.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ String[] value();
+}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/errorprone/tests/res/android/content/BroadcastReceiver.java
similarity index 61%
copy from core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
copy to errorprone/tests/res/android/content/BroadcastReceiver.java
index 1e4fdd7..9d066b7 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
+++ b/errorprone/tests/res/android/content/BroadcastReceiver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 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,16 +14,10 @@
* limitations under the License.
*/
-package android.nfc;
+package android.content;
-/**
- * @hide
- */
-oneway interface INfcControllerAlwaysOnStateCallback {
- /**
- * Called whenever the controller always on state changes
- *
- * @param isEnabled true if the state is enabled, false otherwise
- */
- void onControllerAlwaysOnStateChanged(boolean isEnabled);
+public class BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/errorprone/tests/res/android/content/Context.java b/errorprone/tests/res/android/content/Context.java
index 7ba3fbb..323b8dd 100644
--- a/errorprone/tests/res/android/content/Context.java
+++ b/errorprone/tests/res/android/content/Context.java
@@ -20,4 +20,7 @@
public int getUserId() {
return 0;
}
+
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ }
}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/errorprone/tests/res/android/database/ContentObserver.java
similarity index 61%
copy from core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
copy to errorprone/tests/res/android/database/ContentObserver.java
index 1e4fdd7..4c73a10 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
+++ b/errorprone/tests/res/android/database/ContentObserver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 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,16 +14,10 @@
* limitations under the License.
*/
-package android.nfc;
+package android.database;
-/**
- * @hide
- */
-oneway interface INfcControllerAlwaysOnStateCallback {
- /**
- * Called whenever the controller always on state changes
- *
- * @param isEnabled true if the state is enabled, false otherwise
- */
- void onControllerAlwaysOnStateChanged(boolean isEnabled);
+public abstract class ContentObserver {
+ public void onChange(boolean selfChange) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/errorprone/tests/res/android/foo/IColorService.java b/errorprone/tests/res/android/foo/IColorService.java
new file mode 100644
index 0000000..20c8e95
--- /dev/null
+++ b/errorprone/tests/res/android/foo/IColorService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.foo;
+
+import android.annotation.RequiresPermission;
+
+public interface IColorService extends android.os.IInterface {
+ public static final String RED = "red";
+ public static final String BLUE = "blue";
+
+ public void none();
+ @RequiresPermission(RED)
+ public void red();
+ @RequiresPermission(allOf = { RED, BLUE })
+ public void redAndBlue();
+ @RequiresPermission(anyOf = { RED, BLUE })
+ public void redOrBlue();
+}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/errorprone/tests/res/android/os/Handler.java
similarity index 61%
copy from core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
copy to errorprone/tests/res/android/os/Handler.java
index 1e4fdd7..f001896 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
+++ b/errorprone/tests/res/android/os/Handler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 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,16 +14,10 @@
* limitations under the License.
*/
-package android.nfc;
+package android.os;
-/**
- * @hide
- */
-oneway interface INfcControllerAlwaysOnStateCallback {
- /**
- * Called whenever the controller always on state changes
- *
- * @param isEnabled true if the state is enabled, false otherwise
- */
- void onControllerAlwaysOnStateChanged(boolean isEnabled);
+public class Handler {
+ public void handleMessage(Message msg) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/errorprone/tests/res/android/os/IBinder.java
similarity index 61%
copy from core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
copy to errorprone/tests/res/android/os/IBinder.java
index 1e4fdd7..214a396 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
+++ b/errorprone/tests/res/android/os/IBinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 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,16 +14,10 @@
* limitations under the License.
*/
-package android.nfc;
+package android.os;
-/**
- * @hide
- */
-oneway interface INfcControllerAlwaysOnStateCallback {
- /**
- * Called whenever the controller always on state changes
- *
- * @param isEnabled true if the state is enabled, false otherwise
- */
- void onControllerAlwaysOnStateChanged(boolean isEnabled);
+public interface IBinder {
+ public interface DeathRecipient {
+ public void binderDied();
+ }
}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/errorprone/tests/res/android/os/Message.java
similarity index 61%
copy from core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
copy to errorprone/tests/res/android/os/Message.java
index 1e4fdd7..2421263 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
+++ b/errorprone/tests/res/android/os/Message.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 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,16 +14,7 @@
* limitations under the License.
*/
-package android.nfc;
+package android.os;
-/**
- * @hide
- */
-oneway interface INfcControllerAlwaysOnStateCallback {
- /**
- * Called whenever the controller always on state changes
- *
- * @param isEnabled true if the state is enabled, false otherwise
- */
- void onControllerAlwaysOnStateChanged(boolean isEnabled);
+public class Message {
}
diff --git a/libs/WindowManager/Shell/res/drawable/pip_menu_background.xml b/libs/WindowManager/Shell/res/drawable/pip_menu_background.xml
new file mode 100644
index 0000000..29907a6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_menu_background.xml
@@ -0,0 +1,22 @@
+<?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.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#FF000000"/>
+
+ <corners android:radius="@dimen/pip_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 11c1464..dca5985 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -739,14 +739,11 @@
return (isSummary && isSuppressedSummary) || isSuppressedBubble;
}
- private void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
- Executor callbackExecutor) {
+ private void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback) {
if (mBubbleData.isSummarySuppressed(groupKey)) {
mBubbleData.removeSuppressedSummary(groupKey);
if (callback != null) {
- callbackExecutor.execute(() -> {
- callback.accept(mBubbleData.getSummaryKey(groupKey));
- });
+ callback.accept(mBubbleData.getSummaryKey(groupKey));
}
}
}
@@ -1298,8 +1295,10 @@
public void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback,
Executor callbackExecutor) {
mMainExecutor.execute(() -> {
- BubbleController.this.removeSuppressedSummaryIfNecessary(groupKey, callback,
- callbackExecutor);
+ Consumer<String> cb = callback != null
+ ? (key) -> callbackExecutor.execute(() -> callback.accept(key))
+ : null;
+ BubbleController.this.removeSuppressedSummaryIfNecessary(groupKey, cb);
});
}
@@ -1340,10 +1339,13 @@
@Override
public boolean handleDismissalInterception(BubbleEntry entry,
- @Nullable List<BubbleEntry> children, IntConsumer removeCallback) {
+ @Nullable List<BubbleEntry> children, IntConsumer removeCallback,
+ Executor callbackExecutor) {
+ IntConsumer cb = removeCallback != null
+ ? (index) -> callbackExecutor.execute(() -> removeCallback.accept(index))
+ : null;
return mMainExecutor.executeBlockingForResult(() -> {
- return BubbleController.this.handleDismissalInterception(entry, children,
- removeCallback);
+ return BubbleController.this.handleDismissalInterception(entry, children, cb);
}, Boolean.class);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 9fc8aef..1bfb619 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -140,7 +140,7 @@
* @return true if we want to intercept the dismissal of the entry, else false.
*/
boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
- IntConsumer removeCallback);
+ IntConsumer removeCallback, Executor callbackExecutor);
/** Set the proxy to commnuicate with SysUi side components. */
void setSysuiProxy(SysuiProxy proxy);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 5c3af3e..8ac9a7a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -37,6 +37,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Controller class of PiP animations (both from and to PiP mode).
@@ -112,6 +113,7 @@
PipTransitionAnimator.ofAlpha(taskInfo, leash, destinationBounds, alphaStart,
alphaEnd));
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
+ && Objects.equals(destinationBounds, mCurrentAnimator.getDestinationBounds())
&& mCurrentAnimator.isRunning()) {
mCurrentAnimator.updateEndValue(alphaEnd);
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e152633..e66be66 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -99,9 +99,10 @@
private enum State {
UNDEFINED(0),
TASK_APPEARED(1),
- ENTERING_PIP(2),
- ENTERED_PIP(3),
- EXITING_PIP(4);
+ ENTRY_SCHEDULED(2),
+ ENTERING_PIP(3),
+ ENTERED_PIP(4),
+ EXITING_PIP(5);
private final int mStateValue;
@@ -265,6 +266,13 @@
}
/**
+ * Returns whether the entry animation is waiting to be started.
+ */
+ public boolean isEntryScheduled() {
+ return mState == State.ENTRY_SCHEDULED;
+ }
+
+ /**
* Registers a callback when a display change has been detected when we enter PiP.
*/
public void registerOnDisplayIdChangeCallback(IntConsumer onDisplayIdChangeCallback) {
@@ -492,6 +500,19 @@
}
}
+ /**
+ * Called when the display rotation handling is skipped (e.g. when rotation happens while in
+ * the middle of an entry transition).
+ */
+ public void onDisplayRotationSkipped() {
+ if (isEntryScheduled()) {
+ // The PIP animation is scheduled to start with the previous orientation's bounds,
+ // re-calculate the entry bounds and restart the alpha animation.
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+ enterPipWithAlphaAnimation(destinationBounds, mEnterAnimationDuration);
+ }
+ }
+
@VisibleForTesting
void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) {
// If we are fading the PIP in, then we should move the pip to the final location as
@@ -501,6 +522,7 @@
mSurfaceControlTransactionFactory.getTransaction();
tx.setAlpha(mLeash, 0f);
tx.apply();
+ mState = State.ENTRY_SCHEDULED;
applyEnterPipSyncTransaction(destinationBounds, () -> {
mPipAnimationController
.getAnimator(mTaskInfo, mLeash, destinationBounds, 0f, 1f)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 62ae1d5..f505e60 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -116,7 +116,8 @@
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
if (!mPipTaskOrganizer.isInPip()
|| mPipBoundsState.getDisplayLayout().rotation() == toRotation
- || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
+ || mPipTaskOrganizer.isDeferringEnterPipAnimation()
+ || mPipTaskOrganizer.isEntryScheduled()) {
// Skip if the same rotation has been set or we aren't in PIP or haven't actually
// entered PIP yet. We still need to update the display layout in the bounds handler
// in this case.
@@ -124,6 +125,7 @@
// do not forget to update the movement bounds as well.
updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
+ mPipTaskOrganizer.onDisplayRotationSkipped();
return;
}
// If there is an animation running (ie. from a shelf offset), then ensure that we calculate
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 7e594a4..3c25a13 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -130,7 +130,11 @@
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
inflate(context, R.layout.pip_menu, this);
- mBackgroundDrawable = new ColorDrawable(Color.BLACK);
+ final boolean enableCornerRadius = mContext.getResources()
+ .getBoolean(R.bool.config_pipEnableRoundCorner);
+ mBackgroundDrawable = enableCornerRadius
+ ? mContext.getDrawable(R.drawable.pip_menu_background)
+ : new ColorDrawable(Color.BLACK);
mBackgroundDrawable.setAlpha(0);
mViewRoot = findViewById(R.id.background);
mViewRoot.setBackground(mBackgroundDrawable);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index 98ce274..1f9ff4ab 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -89,6 +89,12 @@
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
@Presubmit
@Test
fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index ef68ed6..87ad8de 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -103,6 +103,12 @@
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index d341bb1..a988148 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -60,6 +60,12 @@
}
}
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
@Presubmit
@Test
fun bothAppWindowsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index 3bf0296..3396b90 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -74,6 +74,12 @@
@Test
override fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
@Presubmit
@Test
fun bothAppWindowsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index 83853e6..512fd9a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -17,11 +17,13 @@
package com.android.wm.shell.flicker.apppairs
import android.view.Surface
+import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.Test
abstract class RotateTwoLaunchedAppsTransition(
testSpec: FlickerTestParameter
@@ -49,4 +51,16 @@
}
}
}
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index bca2576..e50bde2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -23,7 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.WALLPAPER_TITLE
+import com.android.server.wm.flicker.LAUNCHER_TITLE
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -60,9 +60,9 @@
}
override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME, WALLPAPER_TITLE, LIVE_WALLPAPER_PACKAGE_NAME,
+ get() = listOf(LAUNCHER_PACKAGE_NAME, LIVE_WALLPAPER_PACKAGE_NAME,
splitScreenApp.defaultWindowName, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, *LAUNCHER_TITLE)
@FlakyTest(bugId = 169271943)
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index 9717709..64cc853 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -84,7 +84,7 @@
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesInVisible() =
testSpec.appWindowBecomesInVisible(secondaryApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index 3f714bb..2e11551 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -78,7 +78,7 @@
@Test
fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
@@ -87,7 +87,7 @@
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesInVisible() =
testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 72d6f56..39f4ce2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -118,7 +118,7 @@
fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
- @Presubmit
+ @FlakyTest
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index 8f15e50..7cf30ec 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -70,7 +70,7 @@
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(splitScreenApp.getPackage())
@@ -86,7 +86,7 @@
@Test
fun appPairsDividerBecomesVisible() = testSpec.appPairsDividerBecomesVisible()
- @Presubmit
+ @FlakyTest
@Test
fun layerBecomesVisible() = testSpec.layerBecomesVisible(splitScreenApp.getPackage())
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index c914ada..4a59c62 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -92,7 +92,7 @@
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() =
testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index ffb20a4..834821b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -89,7 +89,7 @@
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() =
testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index 9c798d8..db709a0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -98,7 +98,7 @@
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
testSpec.config.endRotation)
- @Presubmit
+ @FlakyTest
@Test
fun appWindowBecomesVisible() =
testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index cd20dde..2609258 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -54,7 +55,7 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
fun pipLayerBecomesVisible() {
testSpec.assertLayers {
@@ -62,7 +63,7 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
fun pipWindowBecomesVisible() {
testSpec.assertWm {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 2beec2e..33ddec37 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -88,6 +88,12 @@
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
@Presubmit
@Test
fun pipAppWindowIsAlwaysOnTop() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
index 0408421..f290b90 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
@@ -16,11 +16,13 @@
package com.android.wm.shell.flicker.pip
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -41,4 +43,16 @@
pipApp.closePipWindow(wmHelper)
}
}
+
+ @FlakyTest
+ @Test
+ override fun pipLayerBecomesInvisible() {
+ super.pipLayerBecomesInvisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun pipWindowBecomesInvisible() {
+ super.pipWindowBecomesInvisible()
+ }
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
index c7a1c9a..4440262 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -67,11 +68,11 @@
@Test
override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 852ee47..0d686f5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -75,7 +76,7 @@
override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
testSpec.config.endRotation, allStates = false)
- @Presubmit
+ @FlakyTest
@Test
override fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index 6f17a2c..f7f658e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -59,7 +58,7 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
fun appReplacesPipWindow() {
testSpec.assertWm {
@@ -69,7 +68,7 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
fun appReplacesPipLayer() {
testSpec.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index ad1ccbd..b4c75a6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -20,6 +20,7 @@
import android.content.Intent
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -167,11 +168,11 @@
@Test
open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 9aab7f3..1e7d08b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -125,6 +125,12 @@
}
}
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index de14beb..c2642d3 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -60,6 +60,14 @@
uniform float viewportWidth; // target height in pixels
uniform float viewportHeight; // target width in pixels
+ // uInterpolationStrength is the intensity of the interpolation.
+ // if uInterpolationStrength is 0, then the stretch is constant for all the
+ // uStretchAffectedDist. if uInterpolationStrength is 1, then stretch intensity
+ // is interpolated based on the pixel position in the uStretchAffectedDist area;
+ // The closer we are from the scroll anchor point, the more it stretches,
+ // and the other way around.
+ uniform float uInterpolationStrength;
+
float easeInCubic(float t, float d) {
float tmp = t * d;
return tmp * tmp * tmp;
@@ -70,10 +78,12 @@
float overscroll,
float uStretchAffectedDist,
float uInverseStretchAffectedDist,
- float distanceStretched
+ float distanceStretched,
+ float interpolationStrength
) {
float offsetPos = uStretchAffectedDist - inPos;
- float posBasedVariation = easeInCubic(offsetPos, uInverseStretchAffectedDist);
+ float posBasedVariation = mix(
+ 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
float stretchIntensity = overscroll * posBasedVariation;
return distanceStretched - (offsetPos / (1. + stretchIntensity));
}
@@ -84,10 +94,12 @@
float reverseStretchDist,
float uStretchAffectedDist,
float uInverseStretchAffectedDist,
- float distanceStretched
+ float distanceStretched,
+ float interpolationStrength
) {
float offsetPos = inPos - reverseStretchDist;
- float posBasedVariation = easeInCubic(offsetPos, uInverseStretchAffectedDist);
+ float posBasedVariation = mix(
+ 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
float stretchIntensity = (-overscroll) * posBasedVariation;
return 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
}
@@ -101,7 +113,8 @@
float uStretchAffectedDist,
float uInverseStretchAffectedDist,
float distanceStretched,
- float distanceDiff
+ float distanceDiff,
+ float interpolationStrength
) {
float outPos = inPos;
if (overscroll > 0) {
@@ -111,7 +124,8 @@
overscroll,
uStretchAffectedDist,
uInverseStretchAffectedDist,
- distanceStretched
+ distanceStretched,
+ interpolationStrength
);
} else if (inPos >= distanceStretched) {
outPos = distanceDiff + inPos;
@@ -126,7 +140,8 @@
stretchAffectedDist,
uStretchAffectedDist,
uInverseStretchAffectedDist,
- distanceStretched
+ distanceStretched,
+ interpolationStrength
);
} else if (inPos < stretchAffectedDist) {
outPos = -distanceDiff + inPos;
@@ -153,7 +168,8 @@
uStretchAffectedDistX,
uInverseDistanceStretchedX,
uDistanceStretchedX,
- uDistDiffX
+ uDistDiffX,
+ uInterpolationStrength
);
outV = computeOverscroll(
inV,
@@ -161,7 +177,8 @@
uStretchAffectedDistY,
uInverseDistanceStretchedY,
uDistanceStretchedY,
- uDistDiffY
+ uDistDiffY,
+ uInterpolationStrength
);
coord.x = outU * viewportWidth;
coord.y = outV * viewportHeight;
@@ -170,6 +187,7 @@
static const float ZERO = 0.f;
static const float CONTENT_DISTANCE_STRETCHED = 1.f;
+static const float INTERPOLATION_STRENGTH_VALUE = 0.7f;
sk_sp<SkShader> StretchEffect::getShader(const sk_sp<SkImage>& snapshotImage) const {
if (isEmpty()) {
@@ -197,6 +215,7 @@
mBuilder->child("uContentTexture") = snapshotImage->makeShader(
SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear));
+ mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1);
mBuilder->uniform("uStretchAffectedDistX").set(&CONTENT_DISTANCE_STRETCHED, 1);
mBuilder->uniform("uStretchAffectedDistY").set(&CONTENT_DISTANCE_STRETCHED, 1);
mBuilder->uniform("uDistanceStretchedX").set(&distanceStretchedX, 1);
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 71f533c..ab00dd5 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -24,6 +24,7 @@
#include "SkClipStack.h"
#include "SkRect.h"
#include "SkM44.h"
+#include "utils/GLUtils.h"
namespace android {
namespace uirenderer {
@@ -170,6 +171,8 @@
setScissor(info.height, clipRegion.getBounds());
}
+ // WebView may swallow GL errors, so catch them here
+ GL_CHECKPOINT(LOW);
mWebViewHandle->drawGl(info);
if (clearStencilAfterFunctor) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b2a9863..2482188 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -658,10 +658,14 @@
if (gpuCompleteTime == -1) {
gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted);
}
- if (gpuCompleteTime < frameInfo->get(FrameInfoIndex::SwapBuffers)) {
- // TODO (b/180488606): Investigate why this can happen for first frames.
- ALOGW("Impossible GPU complete time swapBuffers=%" PRIi64 " gpuComplete=%" PRIi64,
- frameInfo->get(FrameInfoIndex::SwapBuffers), gpuCompleteTime);
+ if (gpuCompleteTime < frameInfo->get(FrameInfoIndex::IssueDrawCommandsStart)) {
+ // On Vulkan the GPU commands are flushed to the GPU during IssueDrawCommands rather
+ // than after SwapBuffers. So if the GPU signals before issue draw commands, then
+ // something probably went wrong. Anything after that could just be expected
+ // pipeline differences
+ ALOGW("Impossible GPU complete time issueCommandsStart=%" PRIi64
+ " gpuComplete=%" PRIi64,
+ frameInfo->get(FrameInfoIndex::IssueDrawCommandsStart), gpuCompleteTime);
gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted);
}
frameInfo->set(FrameInfoIndex::FrameCompleted) = gpuCompleteTime;
diff --git a/libs/hwui/tests/scripts/skp-capture.sh b/libs/hwui/tests/scripts/skp-capture.sh
index 4b46fbf..0749a8d 100755
--- a/libs/hwui/tests/scripts/skp-capture.sh
+++ b/libs/hwui/tests/scripts/skp-capture.sh
@@ -76,8 +76,8 @@
# so we continue to show the "waiting for app interaction" message as long as the app still requires
# interaction to draw more frames.
adb_test_file_nonzero() {
- # grab first byte of `du` output
- X="$(adb shell "du \"$1\" 2> /dev/null | dd bs=1 count=1 2> /dev/null")"
+ # grab first byte of `wc -c` output
+ X="$(adb shell "wc -c \"$1\" 2> /dev/null | dd bs=1 count=1 2> /dev/null")"
test "$X" && test "$X" -ne 0
}
timeout=$(( $(date +%s) + $phase1_timeout_seconds))
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 85d1bc5..4dc1cca 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6887,7 +6887,6 @@
*
* @return true if successful, otherwise false
*/
- @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
try {
return getService().getEncodedSurroundMode(
@@ -6944,7 +6943,6 @@
*
* @return whether the required surround format is enabled
*/
- @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
try {
return getService().isSurroundFormatEnabled(audioFormat);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 864350e..3a19b13 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -2495,7 +2495,10 @@
* The default security level is defined as the highest security level
* supported on the device.
*
- * @param mime The mime type of the media data
+ * @param mime The mime type of the media data. Please use {@link
+ * #isCryptoSchemeSupported(UUID, String)} to query mime type support separately;
+ * for unsupported mime types the return value of {@link
+ * #requiresSecureDecoder(String)} is crypto scheme dependent.
*/
public boolean requiresSecureDecoder(@NonNull String mime) {
return requiresSecureDecoder(mime, getMaxSecurityLevel());
@@ -2505,7 +2508,10 @@
* Query if the crypto scheme requires the use of a secure decoder
* to decode data of the given mime type at the given security level.
*
- * @param mime The mime type of the media data
+ * @param mime The mime type of the media data. Please use {@link
+ * #isCryptoSchemeSupported(UUID, String, int)} to query mime type support
+ * separately; for unsupported mime types the return value of {@link
+ * #requiresSecureDecoder(String, int)} is crypto scheme dependent.
* @param level a security level between {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO}
* and {@link #SECURITY_LEVEL_HW_SECURE_ALL}. Otherwise the special value
* {@link #getMaxSecurityLevel()} is also permitted;
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 4719772..9e2cd3e 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -13,7 +13,7 @@
method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackAsUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 63e0fe9..2194575 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -239,6 +239,7 @@
method public final void sendQosSessionLost(int, int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method @Deprecated public void setLegacySubtype(int, @NonNull String);
+ method public void setLingerDuration(@NonNull java.time.Duration);
method public void setTeardownDelayMs(@IntRange(from=0, to=0x1388) int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index c4a0d69..96f2de6 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -5362,10 +5362,10 @@
* {@link #unregisterNetworkCallback(NetworkCallback)}.
*
* @param request {@link NetworkRequest} describing this request.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * If null, the callback is invoked on the default internal Handler.
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
* the callback must not be shared - it uniquely specifies this request.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * If null, the callback is invoked on the default internal Handler.
* @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
* @throws SecurityException if missing the appropriate permissions.
* @throws RuntimeException if the app already has too many callbacks registered.
@@ -5380,7 +5380,8 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
})
public void requestBackgroundNetwork(@NonNull NetworkRequest request,
- @NonNull Handler handler, @NonNull NetworkCallback networkCallback) {
+ @NonNull NetworkCallback networkCallback,
+ @SuppressLint("ListenerLast") @NonNull Handler handler) {
final NetworkCapabilities nc = request.networkCapabilities;
sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
TYPE_NONE, new CallbackHandler(handler));
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
index 26cb1ed..9a58add 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -42,4 +42,5 @@
void sendQosSessionLost(int qosCallbackId, in QosSession session);
void sendQosCallbackError(int qosCallbackId, int exceptionType);
void sendTeardownDelayMs(int teardownDelayMs);
+ void sendLingerDuration(int durationMs);
}
diff --git a/packages/Connectivity/framework/src/android/net/LinkProperties.java b/packages/Connectivity/framework/src/android/net/LinkProperties.java
index e41ed72..99f48b4 100644
--- a/packages/Connectivity/framework/src/android/net/LinkProperties.java
+++ b/packages/Connectivity/framework/src/android/net/LinkProperties.java
@@ -686,8 +686,8 @@
}
/**
- * Adds a {@link RouteInfo} to this {@code LinkProperties}, if a {@link RouteInfo}
- * with the same {@link RouteInfo.RouteKey} with different properties
+ * Adds a {@link RouteInfo} to this {@code LinkProperties}. If there is a {@link RouteInfo}
+ * with the same destination, gateway and interface with different properties
* (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an
* interface name set and that differs from the interface set for this
* {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index 3622c1c..518d3f3 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
@@ -106,6 +107,9 @@
private final String LOG_TAG;
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ /** @hide */
+ @TestApi
+ public static final int MIN_LINGER_TIMER_MS = 2000;
private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>();
private volatile long mLastBwRefreshTime = 0;
private static final long BW_REFRESH_MIN_WIN_MS = 500;
@@ -391,6 +395,15 @@
*/
public static final int CMD_NETWORK_DESTROYED = BASE + 23;
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to set the linger duration for this network
+ * agent.
+ * arg1 = the linger duration, represents by {@link Duration}.
+ *
+ * @hide
+ */
+ public static final int EVENT_LINGER_DURATION_CHANGED = BASE + 24;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
config.legacyTypeName, config.legacySubTypeName);
@@ -1287,6 +1300,22 @@
queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
}
+ /**
+ * Set the linger duration for this network agent.
+ * @param duration the delay between the moment the network becomes unneeded and the
+ * moment the network is disconnected or moved into the background.
+ * Note that If this duration has greater than millisecond precision, then
+ * the internal implementation will drop any excess precision.
+ */
+ public void setLingerDuration(@NonNull final Duration duration) {
+ Objects.requireNonNull(duration);
+ final long durationMs = duration.toMillis();
+ if (durationMs < MIN_LINGER_TIMER_MS || durationMs > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("Duration must be within ["
+ + MIN_LINGER_TIMER_MS + "," + Integer.MAX_VALUE + "]ms");
+ }
+ queueOrSendMessage(ra -> ra.sendLingerDuration((int) durationMs));
+ }
/** @hide */
protected void log(final String s) {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkProvider.java b/packages/Connectivity/framework/src/android/net/NetworkProvider.java
index cfb7325..0665af5 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkProvider.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkProvider.java
@@ -167,7 +167,15 @@
ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request);
}
- /** @hide */
+ /**
+ * A callback for parties registering a NetworkOffer.
+ *
+ * This is used with {@link ConnectivityManager#offerNetwork}. When offering a network,
+ * the system will use this callback to inform the caller that a network corresponding to
+ * this offer is needed or unneeded.
+ *
+ * @hide
+ */
@SystemApi
public interface NetworkOfferCallback {
/**
diff --git a/packages/Connectivity/framework/src/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java
index b0752e9..7be7deb 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkScore.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkScore.java
@@ -48,7 +48,14 @@
})
public @interface KeepConnectedReason { }
+ /**
+ * Do not keep this network connected if there is no outstanding request for it.
+ */
public static final int KEEP_CONNECTED_NONE = 0;
+ /**
+ * Keep this network connected even if there is no outstanding request for it, because it
+ * is being considered for handover.
+ */
public static final int KEEP_CONNECTED_FOR_HANDOVER = 1;
// Agent-managed policies
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index ba83a44..efd3363 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.net.NetworkCapabilities.RedactionType;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -45,7 +46,7 @@
public final String sessionId;
@Override
- public long getApplicableRedactions() {
+ public @RedactionType long getApplicableRedactions() {
return REDACT_FOR_NETWORK_SETTINGS;
}
@@ -53,7 +54,7 @@
* Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
*/
@NonNull
- public VpnTransportInfo makeCopy(long redactions) {
+ public VpnTransportInfo makeCopy(@RedactionType long redactions) {
return new VpnTransportInfo(type,
((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : sessionId);
}
diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml b/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
index dcbdc07..cec8b32 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/styles_preference.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
<resources>
- <!--DEPRECATED. It will remove after all of client team migrated to new style. -->
+ <!--DEPRECATED. It will be removed after all of client teams migrated to new style. -->
<style name="PreferenceTheme" parent="@style/PreferenceThemeOverlay">
<item name="preferenceCategoryStyle">@style/SettingsCategoryPreference</item>
<item name="preferenceStyle">@style/SettingsPreference</item>
@@ -28,7 +28,7 @@
<item name="footerPreferenceStyle">@style/Preference.Material</item>
</style>
- <style name="SettingsPreferenceTheme" parent="@style/PreferenceThemeOverlay">
+ <style name="PreferenceTheme.SettingsBase" parent="@style/PreferenceThemeOverlay">
<item name="preferenceCategoryStyle">@style/SettingsCategoryPreference</item>
<item name="preferenceStyle">@style/SettingsPreference</item>
<item name="checkBoxPreferenceStyle">@style/SettingsCheckBoxPreference</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/themes.xml b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
index 13c7523..9c096d2 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
@@ -21,7 +21,7 @@
<item name="android:textAppearanceListItem">@style/TextAppearance.PreferenceTitle</item>
<item name="android:listPreferredItemPaddingStart">@dimen/preference_padding_start</item>
<item name="android:listPreferredItemPaddingEnd">@dimen/preference_padding_end</item>
- <item name="preferenceTheme">@style/SettingsPreferenceTheme</item>
+ <item name="preferenceTheme">@style/PreferenceTheme.SettingsBase</item>
</style>
<!-- Using in SubSettings page including injected settings page -->
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 14ccd80..70b826a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1014,6 +1014,9 @@
<!-- Settings item title to select whether to show transcoding notifications. [CHAR LIMIT=85] -->
<string name="transcode_notification">Show transcoding notifications</string>
+ <!-- Settings item title to select whether to disable cache for transcoding. [CHAR LIMIT=85] -->
+ <string name="transcode_disable_cache">Disable transcoding cache</string>
+
<!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
<string name="runningservices_settings_title">Running services</string>
<!-- Services settings screen, setting option summary for the user to go to the screen to view running services -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 91667c4..6440d2a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -16,7 +16,6 @@
package com.android.providers.settings;
-import static android.os.Process.INVALID_UID;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
@@ -364,6 +363,11 @@
mHandler = new Handler(mHandlerThread.getLooper());
mSettingsRegistry = new SettingsRegistry();
}
+ SettingsState.cacheSystemPackageNamesAndSystemSignature(getContext());
+ synchronized (mLock) {
+ mSettingsRegistry.migrateAllLegacySettingsIfNeededLocked();
+ mSettingsRegistry.syncSsaidTableOnStartLocked();
+ }
mHandler.post(() -> {
registerBroadcastReceivers();
startWatchingUserRestrictionChanges();
@@ -2499,8 +2503,6 @@
mHandler = new MyHandler(getContext().getMainLooper());
mGenerationRegistry = new GenerationRegistry(mLock);
mBackupManager = new BackupManager(getContext());
- migrateAllLegacySettingsIfNeeded();
- syncSsaidTableOnStart();
}
private void generateUserKeyLocked(int userId) {
@@ -2587,38 +2589,36 @@
return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid);
}
- public void syncSsaidTableOnStart() {
- synchronized (mLock) {
- // Verify that each user's packages and ssaid's are in sync.
- for (UserInfo user : mUserManager.getAliveUsers()) {
- // Get all uids for the user's packages.
- final List<PackageInfo> packages;
- try {
- packages = mPackageManager.getInstalledPackages(
+ private void syncSsaidTableOnStartLocked() {
+ // Verify that each user's packages and ssaid's are in sync.
+ for (UserInfo user : mUserManager.getAliveUsers()) {
+ // Get all uids for the user's packages.
+ final List<PackageInfo> packages;
+ try {
+ packages = mPackageManager.getInstalledPackages(
PackageManager.MATCH_UNINSTALLED_PACKAGES,
user.id).getList();
- } catch (RemoteException e) {
- throw new IllegalStateException("Package manager not available");
- }
- final Set<String> appUids = new HashSet<>();
- for (PackageInfo info : packages) {
- appUids.add(Integer.toString(info.applicationInfo.uid));
- }
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Package manager not available");
+ }
+ final Set<String> appUids = new HashSet<>();
+ for (PackageInfo info : packages) {
+ appUids.add(Integer.toString(info.applicationInfo.uid));
+ }
- // Get all uids currently stored in the user's ssaid table.
- final Set<String> ssaidUids = new HashSet<>(
- getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id));
- ssaidUids.remove(SSAID_USER_KEY);
+ // Get all uids currently stored in the user's ssaid table.
+ final Set<String> ssaidUids = new HashSet<>(
+ getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id));
+ ssaidUids.remove(SSAID_USER_KEY);
- // Perform a set difference for the appUids and ssaidUids.
- ssaidUids.removeAll(appUids);
+ // Perform a set difference for the appUids and ssaidUids.
+ ssaidUids.removeAll(appUids);
- // If there are ssaidUids left over they need to be removed from the table.
- final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
- user.id);
- for (String uid : ssaidUids) {
- ssaidSettings.deleteSettingLocked(uid);
- }
+ // If there are ssaidUids left over they need to be removed from the table.
+ final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
+ user.id);
+ for (String uid : ssaidUids) {
+ ssaidSettings.deleteSettingLocked(uid);
}
}
}
@@ -2911,7 +2911,7 @@
boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
- setting.getPackageName(), INVALID_UID, userId)) {
+ setting.getPackageName())) {
if (prefix != null && !setting.getName().startsWith(prefix)) {
continue;
}
@@ -2931,7 +2931,7 @@
boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
- setting.getPackageName(), INVALID_UID, userId)) {
+ setting.getPackageName())) {
if (prefix != null && !setting.getName().startsWith(prefix)) {
continue;
}
@@ -3009,40 +3009,38 @@
return mSettingsStates.get(key);
}
- private void migrateAllLegacySettingsIfNeeded() {
- synchronized (mLock) {
- final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
- File globalFile = getSettingsFile(key);
- if (SettingsState.stateFileExists(globalFile)) {
- return;
- }
+ private void migrateAllLegacySettingsIfNeededLocked() {
+ final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
+ File globalFile = getSettingsFile(key);
+ if (SettingsState.stateFileExists(globalFile)) {
+ return;
+ }
- mSettingsCreationBuildId = Build.ID;
+ mSettingsCreationBuildId = Build.ID;
- final long identity = Binder.clearCallingIdentity();
- try {
- List<UserInfo> users = mUserManager.getAliveUsers();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ List<UserInfo> users = mUserManager.getAliveUsers();
- final int userCount = users.size();
- for (int i = 0; i < userCount; i++) {
- final int userId = users.get(i).id;
+ final int userCount = users.size();
+ for (int i = 0; i < userCount; i++) {
+ final int userId = users.get(i).id;
- DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
- SQLiteDatabase database = dbHelper.getWritableDatabase();
- migrateLegacySettingsForUserLocked(dbHelper, database, userId);
+ DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
+ SQLiteDatabase database = dbHelper.getWritableDatabase();
+ migrateLegacySettingsForUserLocked(dbHelper, database, userId);
- // Upgrade to the latest version.
- UpgradeController upgrader = new UpgradeController(userId);
- upgrader.upgradeIfNeededLocked();
+ // Upgrade to the latest version.
+ UpgradeController upgrader = new UpgradeController(userId);
+ upgrader.upgradeIfNeededLocked();
- // Drop from memory if not a running user.
- if (!mUserManager.isUserRunning(new UserHandle(userId))) {
- removeUserStateLocked(userId, false);
- }
+ // Drop from memory if not a running user.
+ if (!mUserManager.isUserRunning(new UserHandle(userId))) {
+ removeUserStateLocked(userId, false);
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
@@ -5036,19 +5034,9 @@
// In the upgrade case we pretend the call is made from the app
// that made the last change to the setting to properly determine
// whether the call has been made by a system component.
- int callingUid = -1;
try {
- callingUid = mPackageManager.getPackageUid(setting.getPackageName(), 0, userId);
- } catch (RemoteException e) {
- /* ignore - handled below */
- }
- if (callingUid < 0) {
- Slog.e(LOG_TAG, "Unknown package: " + setting.getPackageName());
- continue;
- }
- try {
- final boolean systemSet = SettingsState.isSystemPackage(getContext(),
- setting.getPackageName(), callingUid, userId);
+ final boolean systemSet = SettingsState.isSystemPackage(
+ getContext(), setting.getPackageName());
if (systemSet) {
settings.insertSettingOverrideableByRestoreLocked(name, setting.getValue(),
setting.getTag(), true, setting.getPackageName());
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 53d868a..e7f1ad7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -17,14 +17,13 @@
package com.android.providers.settings;
import static android.os.Process.FIRST_APPLICATION_UID;
-import static android.os.Process.INVALID_UID;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.Signature;
import android.os.Binder;
import android.os.Build;
import android.os.FileUtils;
@@ -37,10 +36,10 @@
import android.providers.settings.SettingsOperationProto;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Base64;
import android.util.Slog;
-import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -149,13 +148,7 @@
private static final String NULL_VALUE = "null";
- private static final Object sLock = new Object();
-
- @GuardedBy("sLock")
- private static final SparseIntArray sSystemUids = new SparseIntArray();
-
- @GuardedBy("sLock")
- private static Signature sSystemSignature;
+ private static final ArraySet<String> sSystemPackages = new ArraySet<>();
private final Object mWriteLock = new Object();
@@ -641,7 +634,7 @@
/**
* Dump historical operations as a proto buf.
*
- * @param proto The proto buf stream to dump to
+ * @param proto The proto buf stream to dump to
* @param fieldId The repeated field ID to use to save an operation to.
*/
void dumpHistoricalOperations(@NonNull ProtoOutputStream proto, long fieldId) {
@@ -1048,6 +1041,7 @@
/**
* Uses AtomicFile to check if the file or its backup exists.
+ *
* @param file The file to check for existence
* @return whether the original or backup exist
*/
@@ -1307,9 +1301,9 @@
if (NULL_VALUE.equals(value)) {
value = null;
}
-
final boolean callerSystem = !forceNonSystemPackage &&
- !isNull() && isSystemPackage(mContext, packageName);
+ !isNull() && (isCalledFromSystem(packageName)
+ || isSystemPackage(mContext, packageName));
// Settings set by the system are always defaults.
if (callerSystem) {
setDefault = true;
@@ -1434,98 +1428,98 @@
return sb.toString();
}
- // Check if a specific package belonging to the caller is part of the system package.
- public static boolean isSystemPackage(Context context, String packageName) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- return isSystemPackage(context, packageName, callingUid, callingUserId);
+ // Cache the list of names of system packages. This is only called once on system boot.
+ public static void cacheSystemPackageNamesAndSystemSignature(@NonNull Context context) {
+ final PackageManager packageManager = context.getPackageManager();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ sSystemPackages.add(SYSTEM_PACKAGE_NAME);
+ // Cache SetupWizard package name.
+ final String setupWizPackageName = packageManager.getSetupWizardPackageName();
+ if (setupWizPackageName != null) {
+ sSystemPackages.add(setupWizPackageName);
+ }
+ final List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
+ final int installedPackagesCount = packageInfos.size();
+ for (int i = 0; i < installedPackagesCount; i++) {
+ if (shouldAddToSystemPackages(packageInfos.get(i))) {
+ sSystemPackages.add(packageInfos.get(i).packageName);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
- // Check if a specific package, uid, and user ID are part of the system package.
- public static boolean isSystemPackage(Context context, String packageName, int uid,
- int userId) {
- synchronized (sLock) {
- if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
- return true;
- }
-
- // Shell and Root are not considered a part of the system
- if (SHELL_PACKAGE_NAME.equals(packageName)
- || ROOT_PACKAGE_NAME.equals(packageName)) {
- return false;
- }
-
- if (uid != INVALID_UID) {
- // Native services running as a special UID get a pass
- final int callingAppId = UserHandle.getAppId(uid);
- if (callingAppId < FIRST_APPLICATION_UID) {
- sSystemUids.put(callingAppId, callingAppId);
- return true;
- }
- }
-
- final long identity = Binder.clearCallingIdentity();
- try {
- try {
- uid = context.getPackageManager().getPackageUidAsUser(packageName, 0, userId);
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
-
- // If the system or a special system UID (like telephony), done.
- if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) {
- sSystemUids.put(uid, uid);
- return true;
- }
-
- // If already known system component, done.
- if (sSystemUids.indexOfKey(uid) >= 0) {
- return true;
- }
-
- // If SetupWizard, done.
- String setupWizPackage = context.getPackageManager().getSetupWizardPackageName();
- if (packageName.equals(setupWizPackage)) {
- sSystemUids.put(uid, uid);
- return true;
- }
-
- // If a persistent system app, done.
- PackageInfo packageInfo;
- try {
- packageInfo = context.getPackageManager().getPackageInfoAsUser(
- packageName, PackageManager.GET_SIGNATURES, userId);
- if ((packageInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_PERSISTENT) != 0
- && (packageInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_SYSTEM) != 0) {
- sSystemUids.put(uid, uid);
- return true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
-
- // Last check if system signed.
- if (sSystemSignature == null) {
- try {
- sSystemSignature = context.getPackageManager().getPackageInfoAsUser(
- SYSTEM_PACKAGE_NAME, PackageManager.GET_SIGNATURES,
- UserHandle.USER_SYSTEM).signatures[0];
- } catch (PackageManager.NameNotFoundException e) {
- /* impossible */
- return false;
- }
- }
- if (sSystemSignature.equals(packageInfo.signatures[0])) {
- sSystemUids.put(uid, uid);
- return true;
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
+ private static boolean shouldAddToSystemPackages(@NonNull PackageInfo packageInfo) {
+ // Shell and Root are not considered a part of the system
+ if (isShellOrRoot(packageInfo.packageName)) {
return false;
}
+ // Already added
+ if (sSystemPackages.contains(packageInfo.packageName)) {
+ return false;
+ }
+ return isSystemPackage(packageInfo.applicationInfo);
+ }
+
+ private static boolean isShellOrRoot(@NonNull String packageName) {
+ return (SHELL_PACKAGE_NAME.equals(packageName)
+ || ROOT_PACKAGE_NAME.equals(packageName));
+ }
+
+ private static boolean isCalledFromSystem(@NonNull String packageName) {
+ // Shell and Root are not considered a part of the system
+ if (isShellOrRoot(packageName)) {
+ return false;
+ }
+ final int callingUid = Binder.getCallingUid();
+ // Native services running as a special UID get a pass
+ final int callingAppId = UserHandle.getAppId(callingUid);
+ return (callingAppId < FIRST_APPLICATION_UID);
+ }
+
+ public static boolean isSystemPackage(@NonNull Context context, @NonNull String packageName) {
+ // Check shell or root before trying to retrieve ApplicationInfo to fail fast
+ if (isShellOrRoot(packageName)) {
+ return false;
+ }
+ // If it's a known system package or known to be platform signed
+ if (sSystemPackages.contains(packageName)) {
+ return true;
+ }
+
+ ApplicationInfo aInfo = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ try {
+ // Notice that this makes a call to package manager inside the lock
+ aInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return isSystemPackage(aInfo);
+ }
+
+ private static boolean isSystemPackage(@Nullable ApplicationInfo aInfo) {
+ if (aInfo == null) {
+ return false;
+ }
+ // If the system or a special system UID (like telephony), done.
+ if (aInfo.uid < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ // If a persistent system app, done.
+ if ((aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+ && (aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return true;
+ }
+ // Platform signed packages are considered to be from the system
+ if (aInfo.isSignedWithPlatformKey()) {
+ return true;
+ }
+ return false;
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bef6423f..f685d88 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -113,6 +113,8 @@
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<!-- ACCESS_BACKGROUND_LOCATION is needed for testing purposes only. -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <!-- ACCESS_MTP is needed for testing purposes only. -->
+ <uses-permission android:name="android.permission.ACCESS_MTP" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -539,6 +541,9 @@
<!-- Permission required for CTS test - CtsRotationResolverServiceDeviceTestCases -->
<uses-permission android:name="android.permission.MANAGE_ROTATION_RESOLVER" />
+ <!-- Permission required for CTS test - CtsUwbTestCases -->
+ <uses-permission android:name="android.permission.UWB_PRIVILEGED" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index da78a7c..3363f8e 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -313,12 +313,14 @@
}
context.mainExecutor.execute {
- startAnimation(remoteAnimationTargets, iRemoteAnimationFinishedCallback)
+ startAnimation(remoteAnimationTargets, remoteAnimationNonAppTargets,
+ iRemoteAnimationFinishedCallback)
}
}
private fun startAnimation(
remoteAnimationTargets: Array<out RemoteAnimationTarget>,
+ remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
iCallback: IRemoteAnimationFinishedCallback
) {
val window = remoteAnimationTargets.firstOrNull {
@@ -332,7 +334,7 @@
return
}
- val navigationBar = remoteAnimationTargets.firstOrNull {
+ val navigationBar = remoteAnimationNonAppTargets.firstOrNull {
it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 35423a9..53ff9f0 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -58,5 +58,7 @@
/** View to which this plugin can be registered, in order to get updates. */
interface SmartspaceView {
void registerDataProvider(BcSmartspaceDataPlugin plugin);
+
+ void setPrimaryTextColor(int color);
}
}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 00c27bf..1cef44b 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -79,7 +79,6 @@
android:id="@+id/left_aligned_notification_icon_container"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_shelf_height"
- android:layout_marginTop="@dimen/widget_vertical_padding"
android:layout_below="@id/keyguard_status_area"
android:paddingStart="@dimen/below_clock_padding_start"
/>
diff --git a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
index f35f5d1..6725a26 100644
--- a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
+++ b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
@@ -15,10 +15,12 @@
~ limitations under the License.
-->
+
<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<solid
- android:color="@color/notif_pill_background"
+ android:color="?androidprv:attr/colorSurface"
/>
<corners android:radius="20dp" />
diff --git a/packages/SystemUI/res/drawable/qs_detail_background.xml b/packages/SystemUI/res/drawable/qs_detail_background.xml
index 76045e4..e5c7352 100644
--- a/packages/SystemUI/res/drawable/qs_detail_background.xml
+++ b/packages/SystemUI/res/drawable/qs_detail_background.xml
@@ -18,7 +18,7 @@
<inset>
<shape>
<solid android:color="@color/qs_detail_transition"/>
- <corners android:radius="?android:attr/dialogCornerRadius" />
+ <corners android:radius="@dimen/qs_footer_action_corner_radius" />
</shape>
</inset>
</item>
@@ -26,7 +26,7 @@
<inset>
<shape>
<solid android:color="?android:attr/colorBackgroundFloating"/>
- <corners android:radius="?android:attr/dialogCornerRadius" />
+ <corners android:radius="@dimen/qs_footer_action_corner_radius" />
</shape>
</inset>
</item>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml b/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
index 34675ab..6022206 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_chip_background.xml
@@ -23,14 +23,14 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/qs_footer_action_border"/>
<solid android:color="@android:color/transparent"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml b/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml
index 596ed71..bbcfb15 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_chip_background_borderless.xml
@@ -22,13 +22,13 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/transparent"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index dc9d920..bb82f91 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -17,10 +17,11 @@
<com.android.systemui.statusbar.notification.row.NotificationSnooze
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:background="?android:attr/colorBackground"
+ android:background="?androidprv:attr/colorSurface"
android:theme="@style/Theme.SystemUI">
<RelativeLayout
@@ -34,7 +35,7 @@
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
+ android:paddingStart="@*android:dimen/notification_content_margin_end"
android:textColor="?android:attr/textColorPrimary"
android:paddingEnd="4dp"/>
diff --git a/packages/SystemUI/res/layout/notification_snooze_option.xml b/packages/SystemUI/res/layout/notification_snooze_option.xml
index f203839..d42cc02 100644
--- a/packages/SystemUI/res/layout/notification_snooze_option.xml
+++ b/packages/SystemUI/res/layout/notification_snooze_option.xml
@@ -17,8 +17,8 @@
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_marginStart="@*android:dimen/notification_content_margin_start"
+ android:layout_height="@*android:dimen/notification_headerless_min_height"
+ android:layout_marginStart="@*android:dimen/notification_content_margin_end"
android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
android:gravity="center_vertical"
android:textSize="14sp"
diff --git a/packages/SystemUI/res/layout/people_space_initial_layout.xml b/packages/SystemUI/res/layout/people_space_initial_layout.xml
new file mode 100644
index 0000000..ec29d18
--- /dev/null
+++ b/packages/SystemUI/res/layout/people_space_initial_layout.xml
@@ -0,0 +1,69 @@
+<!--
+ ~ 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:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:theme="@android:style/Theme.DeviceDefault.DayNight"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:background="@drawable/people_space_tile_view_card"
+ android:id="@+id/item"
+ android:orientation="horizontal"
+ android:gravity="center"
+ android:layout_gravity="top"
+ android:paddingVertical="16dp"
+ android:paddingHorizontal="16dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:paddingEnd="20dp"
+ android:gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:background="@drawable/ic_person"
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
+
+ <TextView
+ android:id="@+id/name"
+ android:paddingTop="2dp"
+ android:text="@string/empty_user_name"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="12sp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <TextView
+ android:text="@string/status_before_loading"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="12sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="3"
+ android:ellipsize="end" />
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
index b85d6b0..2402bd7 100644
--- a/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
+++ b/packages/SystemUI/res/layout/people_space_placeholder_layout.xml
@@ -14,63 +14,56 @@
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
+
<LinearLayout
android:background="@drawable/people_space_tile_view_card"
android:id="@+id/item"
- android:orientation="vertical"
+ android:orientation="horizontal"
+ android:gravity="center"
+ android:layout_gravity="top"
+ android:paddingVertical="16dp"
+ android:paddingHorizontal="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
- android:orientation="horizontal"
- android:gravity="center"
- android:paddingVertical="2dp"
- android:paddingHorizontal="8dp"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:orientation="vertical"
+ android:paddingEnd="20dp"
+ android:gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
<ImageView
android:background="@drawable/ic_person"
- android:id="@+id/person_icon_only"
- android:layout_width="60dp"
- android:layout_height="60dp"/>
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
- <LinearLayout
- android:orientation="vertical"
- android:paddingStart="8dp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/availability"
- android:layout_width="10dp"
- android:layout_height="10dp"
- android:background="@drawable/circle_green_10dp"/>
- <TextView
- android:id="@+id/name"
- android:text="@string/empty_user_name"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"
- android:maxLines="1"
- android:ellipsize="end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <TextView
- android:id="@+id/last_interaction"
- android:text="@string/empty_status"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="12sp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="3"
- android:ellipsize="end"/>
- </LinearLayout>
+ <TextView
+ android:id="@+id/name"
+ android:paddingTop="2dp"
+ android:text="@string/empty_user_name"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="12sp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
</LinearLayout>
+
+ <TextView
+ android:text="@string/empty_status"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:textSize="12sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="3"
+ android:ellipsize="end" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 7cce1ba..6a1be81 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -45,8 +45,6 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:paddingLeft="@dimen/qs_tile_layout_margin_side"
- android:paddingRight="@dimen/qs_tile_layout_margin_side"
android:paddingBottom="28dp"
android:clipToPadding="false"
android:scrollIndicators="top"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 0217972..343b398 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-** Copyright 2012, The Android Open Source Project
+** 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.
@@ -16,8 +16,7 @@
-->
<!-- Extends FrameLayout -->
-<com.android.systemui.qs.QSFooterView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.qs.QSFooterView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/qs_footer"
android:layout_width="match_parent"
android:layout_height="@dimen/qs_footer_height"
@@ -32,77 +31,70 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:gravity="end" >
+ android:orientation="vertical">
- <com.android.keyguard.AlphaOptimizedLinearLayout
- android:id="@+id/qs_footer_actions_edit_container"
- android:layout_width="@integer/qs_footer_actions_width"
- android:layout_height="match_parent"
- android:layout_weight="@integer/qs_footer_actions_weight"
- android:gravity="center_vertical|start" >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical">
+
+ <TextView
+ android:id="@+id/build"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/qs_tile_margin_horizontal"
+ android:paddingEnd="4dp"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:ellipsize="marquee"
+ android:focusable="true"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.QS.Status"
+ android:visibility="gone" />
+
+ <com.android.systemui.qs.PageIndicator
+ android:id="@+id/footer_page_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:visibility="gone" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/qs_footer_actions_container"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:gravity="center_vertical">
+
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@android:id/edit"
- android:layout_width="@dimen/qs_footer_action_button_size"
+ android:layout_width="0dp"
android:layout_height="@dimen/qs_footer_action_button_size"
- android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+ android:layout_weight="1"
+ android:background="@drawable/qs_footer_action_chip_background"
android:clickable="true"
android:clipToPadding="false"
android:contentDescription="@string/accessibility_quick_settings_edit"
android:focusable="true"
android:padding="@dimen/qs_footer_icon_padding"
android:src="@*android:drawable/ic_mode_edit"
- android:tint="?android:attr/colorForeground"/>
-
- <TextView
- android:id="@+id/build"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:clickable="true"
- android:gravity="center_vertical"
- android:focusable="true"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="@style/TextAppearance.QS.Status"
- android:layout_marginEnd="4dp"
- android:visibility="gone"/>
- </com.android.keyguard.AlphaOptimizedLinearLayout>
-
- <com.android.systemui.qs.PageIndicator
- android:id="@+id/footer_page_indicator"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:visibility="gone" />
-
- <com.android.keyguard.AlphaOptimizedLinearLayout
- android:id="@+id/qs_footer_actions_container"
- android:layout_width="@integer/qs_footer_actions_width"
- android:layout_height="match_parent"
- android:layout_weight="@integer/qs_footer_actions_weight"
- android:gravity="center_vertical|end" >
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/pm_lite"
- android:layout_width="@dimen/qs_footer_action_button_size"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:clickable="true"
- android:clipToPadding="false"
- android:contentDescription="@string/accessibility_quick_settings_power_menu"
- android:focusable="true"
- android:padding="@dimen/qs_footer_icon_padding"
- android:src="@*android:drawable/ic_lock_power_off"
- android:tint="?android:attr/colorForeground"
- android:visibility="gone"
- />
+ android:tint="?android:attr/colorForeground" />
<com.android.systemui.statusbar.phone.MultiUserSwitch
android:id="@+id/multi_user_switch"
- android:layout_width="@dimen/qs_footer_action_button_size"
+ android:layout_width="0dp"
android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_alignParentEnd="true"
- android:background="@drawable/ripple_drawable"
+ android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+ android:layout_weight="1"
+ android:background="@drawable/qs_footer_action_chip_background"
android:focusable="true">
<ImageView
@@ -110,40 +102,58 @@
android:layout_width="@dimen/multi_user_avatar_expanded_size"
android:layout_height="@dimen/multi_user_avatar_expanded_size"
android:layout_gravity="center"
- android:scaleType="centerInside"/>
+ android:scaleType="centerInside" />
</com.android.systemui.statusbar.phone.MultiUserSwitch>
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/settings_button_container"
- android:layout_width="@dimen/qs_footer_action_button_size"
+ android:layout_width="0dp"
android:layout_height="@dimen/qs_footer_action_button_size"
+ android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+ android:background="@drawable/qs_footer_action_chip_background"
+ android:layout_weight="1"
android:clipChildren="false"
android:clipToPadding="false">
<com.android.systemui.statusbar.phone.SettingsButton
android:id="@+id/settings_button"
- style="@android:style/Widget.Material.Button.Borderless"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/qs_footer_action_button_size"
android:layout_gravity="center"
- android:padding="@dimen/qs_footer_icon_padding"
- android:background="@drawable/ripple_drawable"
android:contentDescription="@string/accessibility_quick_settings_settings"
- android:src="@drawable/ic_settings"
+ android:background="@drawable/qs_footer_action_chip_background_borderless"
+ android:padding="@dimen/qs_footer_icon_padding"
android:scaleType="centerInside"
- android:tint="?android:attr/colorForeground"/>
+ android:src="@drawable/ic_settings"
+ android:tint="?android:attr/colorForeground" />
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/tuner_icon"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingStart="36dp"
- android:paddingEnd="4dp"
+ android:layout_width="8dp"
+ android:layout_height="8dp"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_marginBottom="@dimen/qs_footer_icon_padding"
android:src="@drawable/tuner"
android:tint="?android:attr/textColorTertiary"
- android:visibility="invisible"/>
+ android:visibility="invisible" />
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
- </com.android.keyguard.AlphaOptimizedLinearLayout>
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/pm_lite"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/qs_footer_action_button_size"
+ android:layout_weight="1"
+ android:background="@drawable/qs_footer_action_chip_background"
+ android:clickable="true"
+ android:clipToPadding="false"
+ android:focusable="true"
+ android:padding="@dimen/qs_footer_icon_padding"
+ android:src="@*android:drawable/ic_lock_power_off"
+ android:contentDescription="@string/accessibility_quick_settings_power_menu"
+ android:tint="?android:attr/colorForeground" />
+
+ </LinearLayout>
</LinearLayout>
+
</com.android.systemui.qs.QSFooterView>
diff --git a/packages/SystemUI/res/layout/qs_footer_impl_two_lines.xml b/packages/SystemUI/res/layout/qs_footer_impl_two_lines.xml
deleted file mode 100644
index 343b398..0000000
--- a/packages/SystemUI/res/layout/qs_footer_impl_two_lines.xml
+++ /dev/null
@@ -1,159 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2021, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
--->
-
-<!-- Extends FrameLayout -->
-<com.android.systemui.qs.QSFooterView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/qs_footer"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qs_footer_height"
- android:layout_marginStart="@dimen/qs_footer_margin"
- android:layout_marginEnd="@dimen/qs_footer_margin"
- android:background="@android:color/transparent"
- android:baselineAligned="false"
- android:clickable="false"
- android:clipChildren="false"
- android:clipToPadding="false">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_gravity="center_vertical">
-
- <TextView
- android:id="@+id/build"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:paddingStart="@dimen/qs_tile_margin_horizontal"
- android:paddingEnd="4dp"
- android:layout_weight="1"
- android:clickable="true"
- android:ellipsize="marquee"
- android:focusable="true"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.QS.Status"
- android:visibility="gone" />
-
- <com.android.systemui.qs.PageIndicator
- android:id="@+id/footer_page_indicator"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:visibility="gone" />
-
- <View
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" />
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/qs_footer_actions_container"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:gravity="center_vertical">
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@android:id/edit"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
- android:layout_weight="1"
- android:background="@drawable/qs_footer_action_chip_background"
- android:clickable="true"
- android:clipToPadding="false"
- android:contentDescription="@string/accessibility_quick_settings_edit"
- android:focusable="true"
- android:padding="@dimen/qs_footer_icon_padding"
- android:src="@*android:drawable/ic_mode_edit"
- android:tint="?android:attr/colorForeground" />
-
- <com.android.systemui.statusbar.phone.MultiUserSwitch
- android:id="@+id/multi_user_switch"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
- android:layout_weight="1"
- android:background="@drawable/qs_footer_action_chip_background"
- android:focusable="true">
-
- <ImageView
- android:id="@+id/multi_user_avatar"
- android:layout_width="@dimen/multi_user_avatar_expanded_size"
- android:layout_height="@dimen/multi_user_avatar_expanded_size"
- android:layout_gravity="center"
- android:scaleType="centerInside" />
- </com.android.systemui.statusbar.phone.MultiUserSwitch>
-
- <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
- android:id="@+id/settings_button_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
- android:background="@drawable/qs_footer_action_chip_background"
- android:layout_weight="1"
- android:clipChildren="false"
- android:clipToPadding="false">
-
- <com.android.systemui.statusbar.phone.SettingsButton
- android:id="@+id/settings_button"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_gravity="center"
- android:contentDescription="@string/accessibility_quick_settings_settings"
- android:background="@drawable/qs_footer_action_chip_background_borderless"
- android:padding="@dimen/qs_footer_icon_padding"
- android:scaleType="centerInside"
- android:src="@drawable/ic_settings"
- android:tint="?android:attr/colorForeground" />
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/tuner_icon"
- android:layout_width="8dp"
- android:layout_height="8dp"
- android:layout_gravity="center_horizontal|bottom"
- android:layout_marginBottom="@dimen/qs_footer_icon_padding"
- android:src="@drawable/tuner"
- android:tint="?android:attr/textColorTertiary"
- android:visibility="invisible" />
-
- </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/pm_lite"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_weight="1"
- android:background="@drawable/qs_footer_action_chip_background"
- android:clickable="true"
- android:clipToPadding="false"
- android:focusable="true"
- android:padding="@dimen/qs_footer_icon_padding"
- android:src="@*android:drawable/ic_lock_power_off"
- android:contentDescription="@string/accessibility_quick_settings_power_menu"
- android:tint="?android:attr/colorForeground" />
-
- </LinearLayout>
- </LinearLayout>
-
-</com.android.systemui.qs.QSFooterView>
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
index 5c8b2b0..c830773 100644
--- a/packages/SystemUI/res/layout/qs_paged_page.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,8 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<view
- class="com.android.systemui.qs.PagedTileLayout$TilePage"
+<com.android.systemui.qs.SideLabelTileLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tile_page"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml b/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
deleted file mode 100644
index c830773..0000000
--- a/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.systemui.qs.SideLabelTileLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tile_page"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false" />
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 46a7cf6..c3f1113 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -22,5 +22,4 @@
android:layout_height="0dp"
android:layout_weight="1"
android:clipChildren="true"
- android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
-</com.android.systemui.qs.PagedTileLayout>
+ android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom" />
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout_side_labels.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout_side_labels.xml
deleted file mode 100644
index efa2403..0000000
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout_side_labels.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.systemui.qs.PagedTileLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@+id/qs_pager"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:clipChildren="true"
- android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom"
- systemui:sideLabels="true" />
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index dc595ee..3d2a621 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -43,10 +43,7 @@
android:background="@android:color/transparent"
android:focusable="true"
android:accessibilityTraversalBefore="@android:id/edit">
- <ViewStub
- android:id="@+id/qs_footer_stub"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ <include layout="@layout/qs_footer_impl" />
<include layout="@layout/qs_media_divider"
android:id="@+id/divider"/>
</com.android.systemui.qs.QSPanel>
@@ -59,18 +56,4 @@
<include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
android:visibility="gone" />
- <FrameLayout
- android:id="@+id/qs_drag_handle_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:elevation="4dp"
- android:paddingBottom="5dp">
- <View
- android:layout_width="46dp"
- android:layout_height="3dp"
- android:background="@drawable/qs_footer_drag_handle" />
- </FrameLayout>
-
-
</com.android.systemui.qs.QSContainerImpl>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index 5c77d16..91220e5 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -46,6 +46,7 @@
android:layout_gravity="end"
android:background="@drawable/notif_footer_btn_background"
android:focusable="true"
+ android:textColor="@color/notif_pill_text"
android:contentDescription="@string/accessibility_clear_all"
android:text="@string/clear_all_notifications_text"
/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 13367c9..08f23a5 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Vang meer vas"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Maak skermkiekie toe"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Skermkiekievoorskou"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Boonste grens"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Onderste grens"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skermopnemer"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Verwerk tans skermopname"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Deurlopende kennisgewing vir \'n skermopnamesessie"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Invoermetode"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ligging"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ligging af"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokkeer kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Demp mikrofoon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameratoegang"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofoontoegang"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Beskikbaar"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Geblokkeer"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediatoestel"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Net noodoproepe"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skermopname"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Begin"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Om voort te gaan, moet <b><xliff:g id="APP">%s</xliff:g></b> toegang tot jou toestel se mikrofoon hê."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Om voort te gaan, moet <b><xliff:g id="APP">%s</xliff:g></b> toegang tot jou toestel se kamera hê."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokkeer toestelmikrofoon?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokkeer toestelkamera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokkeer toestelkamera en mikrofoon?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou mikrofoon te gebruik."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou kamera te gebruik."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dit deblokkeer toegang vir alle programme en dienste wat toegelaat word om jou kamera of mikrofoon te gebruik."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Toestel"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swiep op om programme te wissel"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Sleep regs om programme vinnig te wissel"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Wekker"</string>
<string name="wallet_title" msgid="5369767670735827105">"Beursie"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Wys alles"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Ontsluit om te betaal"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Gereed"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Stel betaling op"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontsluit om te gebruik"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index f378b4c..3f0789f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ተጨማሪ ይቅረጹ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ቅጽበታዊ ገጽ ዕይታን አሰናብት"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"የቅጽበታዊ ገጽ ዕይታ ቅድመ-ዕይታ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"የላይኛው ወሰን"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"የታችኛው ወሰን"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"የማያ መቅጃ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገጽ ቀረጻን በማሰናዳት ላይ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገጽ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"የግቤት ስልት"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"አካባቢ"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"አካባቢ ጠፍቷል"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ካሜራ አግድ"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"ማይክሮፎንን ድምጸ-ከል አድርግ"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"የካሜራ መዳረሻ"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"የማይክሮፎን መዳረሻ"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ይገኛል"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ታግዷል"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"የሚዲያ መሣሪያ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"የአደጋ ጊዜ ጥሪዎች ብቻ"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"የማያ ገጽ ቀረጻ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ጀምር"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"አቁም"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ለመቀጠል፣ <b><xliff:g id="APP">%s</xliff:g></b> ወደ መሳሪያዎ ማይክሮፎን መድረስ ይፈልጋል።"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ለመቀጠል፣ <b><xliff:g id="APP">%s</xliff:g></b> የመሣሪያዎን ካሜራ መድረስ ይፈልጋል።"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"የመሣሪያ ማይክሮፎን እገዳ ይነሳ?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"የመሣሪያ ካሜራ እገዳ ይነሳ?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"የመሣሪያ ካሜራ እና ማይክሮፎን እገዳ ይነሳ?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ይህ የእርስዎን ማይክሮፎን እንዲጠቀሙ የተፈቀደላቸው የሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻ እገዳን ያነሳል።"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ይህ ካሜራዎን እንዲጠቀሙ ለተፈቀደላቸው ሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻን እገዳ ያነሳል።"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ይህ የእርስዎን ካሜራ ወይም ማይክሮፎን እንዲጠቀሙ የተፈቀደላቸው የሁሉም መተግበሪያዎች እና አገልግሎቶች መዳረሻ እገዳን ያነሳል።"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"መሣሪያ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"መተግበሪያዎችን ለመቀየር ወደ ላይ ያንሸራትቱ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"መተግበሪያዎችን በፍጥነት ለመቀየር ወደ ቀኝ ይጎትቱ"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ኤተርኔት"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"ማንቂያ"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"ሁሉንም አሳይ"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"ለመክፈል ይክፈቱ"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"ዝግጁ"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ክፍያን ያዋቅሩ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ለማየት ይክፈቱ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 475a28b..9daa2b4 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"التقاط المزيد من المحتوى"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"إغلاق لقطة الشاشة"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"معاينة لقطة الشاشة"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"الحد العلوي"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"الحد السفلي"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"مسجّل الشاشة"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
@@ -353,8 +359,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"أسلوب الإدخال"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"الموقع قيد الإيقاف"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"حظر الكاميرا"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"كتم صوت الميكروفون"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"الوصول إلى الكاميرا"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"الوصول إلى الميكروفون"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"متاح"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"محظور"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"جهاز الوسائط"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"مكالمات طوارئ فقط"</string>
@@ -430,8 +438,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"تسجيل الشاشة"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"بدء"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"إيقاف"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"للمتابعة، يحتاج تطبيق <b><xliff:g id="APP">%s</xliff:g></b> إلى الوصول إلى ميكروفون الجهاز."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"للمتابعة، يحتاج تطبيق <b><xliff:g id="APP">%s</xliff:g></b> إلى الوصول إلى كاميرا الجهاز."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"هل تريد إزالة حظر ميكروفون الجهاز؟"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"هل تريد إزالة حظر كاميرا الجهاز؟"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"هل تريد إزالة حظر الكاميرا والميكروفون؟"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الميكروفون."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الكاميرا."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"يؤدي هذا الخيار إلى إزالة حظر الوصول بالنسبة إلى كل التطبيقات والخدمات المسموح لها باستخدام الكاميرا أو الميكروفون."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"الجهاز"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"مرّر سريعًا لأعلى لتبديل التطبيقات"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"اسحب لليسار للتبديل السريع بين التطبيقات"</string>
@@ -669,18 +681,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"إيثرنت"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"المنبّه"</string>
<string name="wallet_title" msgid="5369767670735827105">"المحفظة"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"جاهز"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"إعداد طريقة دفع"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"فتح القفل للاستخدام"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"حدثت مشكلة أثناء الحصول على البطاقات، يُرجى إعادة المحاولة لاحقًا."</string>
<string name="status_bar_work" msgid="5238641949837091056">"الملف الشخصي للعمل"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"وضع الطيران"</string>
<string name="add_tile" msgid="6239678623873086686">"إضافة فئة"</string>
@@ -749,11 +757,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>الحالة:</b> تم خفض الترتيب إلى الوضع صامت"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>الحالة:</b> تمت زيادة الترتيب"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>الحالة:</b> تم خفض الترتيب"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"يتم دائمًا عرض هذه المحادثات في أعلى الإشعارات حتى عندما يكون وضع \"الأولوية\" مفعّلاً."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"الإعدادات"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"المحادثات ذات الأولوية"</string>
<string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"يتعذّر ضبط مجموعة الإشعارات هذه هنا."</string>
@@ -1035,14 +1041,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"الانتقال إلى \"الإعدادات\" لتعديل التنقل داخل النظام"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"تم ضبط المحادثة على أنها ذات أولوية"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"المحادثات ذات الأولوية"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"يتم عرض هذه المحادثات في أعلى القائمة ويمكن دائمًا أن يتم عرضها لك عندما يكون وضع \"الأولوية\" مفعّلاً."</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"يتم عرض صور الملفات الشخصية على شاشة القفل."</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"يمكنك بسهولة العثور على هذه المحادثات في فقاعات المحادثات على شاشتك الرئيسية."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"لا تتقيّد بميزة \"عدم الإزعاج\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"حسنًا"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"الإعدادات"</string>
@@ -1060,18 +1062,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"يمكنك نقل الزر إلى الحافة لإخفائه مؤقتًا."</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"نقل إلى أعلى يمين الشاشة"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"نقل إلى أعلى يسار الشاشة"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"نقل إلى أسفل يمين الشاشة"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"نقل إلى أسفل يسار الشاشة"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"نقله إلى الحافة وإخفاؤه"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"نقله إلى خارج الحافة وإظهاره"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"أدوات التحكم بالأجهزة"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"إضافة عناصر تحكّم لأجهزتك المتصلة"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"إعداد أدوات التحكم بالجهاز"</string>
@@ -1154,35 +1150,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"قبل أقل من <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"قبل أكثر <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"تاريخ الميلاد"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"إنه يوم ميلاد <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"تاريخ ميلاد قريب"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"يَحين يوم ميلاد <xliff:g id="NAME">%1$s</xliff:g> قريبًا."</string>
<string name="anniversary_status" msgid="1790034157507590838">"الذكرى السنوية"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"إنها الذكرى السنوية لـ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"تتم مشاركة الموقع الجغرافي"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"تتم الآن مشاركة موقع <xliff:g id="NAME">%1$s</xliff:g> الجغرافي."</string>
<string name="new_story_status" msgid="9012195158584846525">"قصة جديدة"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"تمت مشاركة قصة جديدة من <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="video_status" msgid="4548544654316843225">"جارٍ المشاهدة"</string>
<string name="audio_status" msgid="4237055636967709208">"يتم الاستماع الآن"</string>
<string name="game_status" msgid="1340694320630973259">"جارٍ اللعب"</string>
<string name="empty_user_name" msgid="3389155775773578300">"الأصدقاء"</string>
<string name="empty_status" msgid="5938893404951307749">"لنجرِ محادثة الليلة."</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"سيظهر المحتوى قريبًا."</string>
<string name="missed_call" msgid="4228016077700161689">"مكالمة فائتة"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"عرض أحدث الرسائل والمكلمات الفائتة وآخر أخبار الحالة"</string>
<string name="people_tile_title" msgid="6589377493334871272">"محادثة"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"تم إرسال رسالة من <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"تم إرسال صورة من <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"حدثت مشكلة أثناء قراءة مقياس مستوى شحن البطارية."</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"انقر للحصول على مزيد من المعلومات."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"لم يتم ضبط منبّه."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 138c227..631ac3e 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"অধিক কেপচাৰ কৰক"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্ৰীনশ্বট অগ্ৰাহ্য কৰক"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্ৰীনশ্বটৰ পূৰ্বদৰ্শন"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ওপৰৰ সীমাৰেখা"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"তলৰ সীমাৰেখা"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্ৰীন ৰেকৰ্ডাৰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রীন ৰেকৰ্ডিঙৰ প্ৰক্ৰিয়াকৰণ হৈ আছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রীণ ৰেকৰ্ডিং ছেশ্বন চলি থকা সময়ত পোৱা জাননী"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ইনপুট পদ্ধতি"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"অৱস্থান"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"অৱস্থান অফ"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"কেমেৰা অৱৰোধ কৰক"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"মাইক্ৰ’ফ’ন মিউট কৰক"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"মিডিয়া ডিভাইচ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"জৰুৰীকালীন কল মাত্ৰ"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"স্ক্ৰীন ৰেকর্ড"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"আৰম্ভ কৰক"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ কৰক"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"অব্যাহত ৰাখিবলৈ <b><xliff:g id="APP">%s</xliff:g></b>এ আপোনাৰ ডিভাইচৰ মাইক্ৰ’ফ’ন এক্সেছ কৰাৰ আৱশ্যক।"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"অব্যাহত ৰাখিবলৈ <b><xliff:g id="APP">%s</xliff:g></b>এ আপোনাৰ ডিভাইচৰ কেমেৰা এক্সেছ কৰাৰ আৱশ্যক।"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইচ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"আনটো এপ্ ব্য়ৱহাৰ কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"খৰতকীয়াকৈ আনটো এপ্ ব্য়ৱহাৰ কৰিবলৈ সোঁফালে টানক"</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ইথাৰনেট"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"এলাৰ্ম"</string>
<string name="wallet_title" msgid="5369767670735827105">"ৱালেট"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"সাজু"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"পৰিশোধ ছেট আপ কৰক"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"আপোনাৰ কাৰ্ড লাভ কৰোঁতে এটা সমস্যা হৈছে, অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক"</string>
<string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লেইন ম\'ড"</string>
<string name="add_tile" msgid="6239678623873086686">"টাইল যোগ দিয়ক"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>স্থিতি:</b> নীৰৱলৈ হ্ৰাস কৰা হৈছে"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>স্থিতি:</b> স্থান ওপৰলৈ কৰা হৈছে"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>স্থিতি:</b> স্থান তললৈ কৰা হৈছে"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"সদায় আপোনাৰ জাননীৰ শীৰ্ষত দেখুওৱা হয় আনকি অগ্ৰাধিকাৰ ম’ডটো অন হৈ থাকিলেও"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"অগ্ৰাধিকাৰপ্ৰাপ্ত বাৰ্তালাপ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"বাৰ্তালাপসমূহ অগ্ৰাধিকাৰপ্ৰাপ্ত হিচাপে ছেট কৰা হৈছে"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"অগ্ৰাধিকাৰপ্ৰাপ্ত বাৰ্তালাপ"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"এই বাৰ্তালাপসমূহ আপোনাৰ সূচীৰ শীৰ্ষত দেখুওৱা হয় আৰু অগ্ৰাধিকাৰ ম’ডটো অন হৈ থাকিলে আপুনি সদায় এইসমূহ পাব পাৰে"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"লক স্ক্ৰীনত প্ৰ’ফাইল চিত্ৰ দেখুওৱা হয়"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"আপুনি নিজৰ গৃহ স্ক্ৰীনৰ বাবলত সহজে এই বাৰ্তালাপসমূহ বিচাৰি পাব পাৰে"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"অসুবিধা নিদিব সুবিধাটোত ব্যাঘাত জন্মাওক"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"বুজি পালোঁ"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ছেটিংসমূহ"</string>
@@ -1040,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"বুটামটোক সাময়িকভাৱে লুকুৱাবলৈ ইয়াক একেবাৰে কাষলৈ লৈ যাওক"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"শীৰ্ষৰ বাওঁফালে নিয়ক"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"তলৰ বাওঁফালে নিয়ক"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"তলৰ সোঁফালে নিয়ক"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"কাষলৈ নিয়ক আৰু লুকুৱাওক"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"কাষৰ বাহিৰলৈ নিয়ক আৰু দেখুৱাওক"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"আপোনাৰ সংযোজিত ডিভাইচসমূহৰ বাবে নিয়ন্ত্ৰণসমূহ যোগ কৰক"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ ছেট আপ কৰক"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>তকৈ কম সময়ৰ পূৰ্বে"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>তকৈ বেছি সময়ৰ পূৰ্বে"</string>
<string name="birthday_status" msgid="2596961629465396761">"জন্মদিন"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"এয়া <xliff:g id="NAME">%1$s</xliff:g>ৰ জন্মদিন"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"জন্মদিন সোনকালে আহি আছে"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g>ৰ জন্মদিন শীঘ্ৰেই আহি আছে"</string>
<string name="anniversary_status" msgid="1790034157507590838">"বৰ্ষপূৰ্তি"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"এয়া <xliff:g id="NAME">%1$s</xliff:g>ৰ বৰ্ষপূৰ্তি"</string>
<string name="location_status" msgid="1294990572202541812">"অৱস্থান শ্বেয়াৰ কৰি থকা হৈছে"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g>এ অৱস্থান শ্বেয়াৰ কৰি আছে"</string>
<string name="new_story_status" msgid="9012195158584846525">"নতুন কাহিনী"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>এ এটা নতুন কাহিনী শ্বেয়াৰ কৰিছে"</string>
<string name="video_status" msgid="4548544654316843225">"চাই আছোঁ"</string>
<string name="audio_status" msgid="4237055636967709208">"শুনি আছোঁ"</string>
<string name="game_status" msgid="1340694320630973259">"প্লে’ হৈ আছে"</string>
<string name="empty_user_name" msgid="3389155775773578300">"বন্ধুবৰ্গ"</string>
<string name="empty_status" msgid="5938893404951307749">"আজি ৰাতি চাট কৰোঁ আহক!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"সমল শীঘ্ৰেই ওলাব"</string>
<string name="missed_call" msgid="4228016077700161689">"মিছড্ কল"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"শেহতীয়া বাৰ্তা, মিছড্ কল আৰু স্থিতিৰ আপডে’ট চাওক"</string>
<string name="people_tile_title" msgid="6589377493334871272">"বাৰ্তালাপ"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>এ এটা বাৰ্তা পঠিয়াইছে"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>এ এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"আপোনাৰ বেটাৰী মিটাৰ পঢ়োঁতে সমস্যা হৈছে"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"অধিক তথ্যৰ বাবে টিপক"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"কোনো এলাৰ্ম ছেট কৰা হোৱা নাই"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 04e9ca0..574c091 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Daha çoxunu əhatə edin"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran şəklini ötürün"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran şəklinə önbaxış"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Yuxarı hüdud"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Aşağı hüdud"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Yazıcısı"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran çəkilişi emal edilir"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekranın video çəkimi ərzində silinməyən bildiriş"</string>
@@ -218,7 +224,7 @@
<string name="accessibility_cell_data" msgid="172950885786007392">"Mobil Data"</string>
<string name="accessibility_cell_data_on" msgid="691666434519443162">"Mobil Data Aktivdir"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Deaktiv"</string>
- <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"Bluetooth tezering."</string>
+ <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"Bluetooth-modem."</string>
<string name="accessibility_airplane_mode" msgid="1899529214045998505">"Uçuş rejimi"</string>
<string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN aktivdir."</string>
<string name="accessibility_no_sims" msgid="5711270400476534667">"SIM kart yoxdur."</string>
@@ -257,7 +263,7 @@
<string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"Təyyarə rejimi deaktiv edildi."</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"Təyyarə rejimi aktiv edildi."</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"tam sakitlik"</string>
- <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"yalnız alarmlar"</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"bildirişlər"</string>
<string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Narahat Etməyin."</string>
<string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\"Narahat etməyin\" deaktivdir."</string>
<string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"\"Narahat etməyin\" aktivdir."</string>
@@ -290,8 +296,8 @@
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"İş rejimi aktivdir."</string>
<string name="accessibility_quick_settings_work_mode_changed_off" msgid="6256690740556798683">"İş rejimi sönülüdür."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"İş rejimi yanılıdır."</string>
- <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Data Qənaəti deaktiv edildi."</string>
- <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Data Qənaəti aktiv edildi."</string>
+ <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Trafikə qənaət edilmir."</string>
+ <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Trafikə qənaət edilir."</string>
<string name="accessibility_quick_settings_sensor_privacy_changed_off" msgid="7608378211873807353">"Sensor Məxfiliyi deaktivdir."</string>
<string name="accessibility_quick_settings_sensor_privacy_changed_on" msgid="4267393685085328801">"Sensor Məxfiliyi aktivdir."</string>
<string name="accessibility_brightness" msgid="5391187016177823721">"Display brightness"</string>
@@ -325,9 +331,9 @@
<string name="start_dreams" msgid="9131802557946276718">"Ekran qoruyucu"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_header_onboarding_text" msgid="1918085351115504765">"Daha çox seçimlər üçün klikləyin və basıb saxlayın"</string>
- <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Narahat Etməyin"</string>
- <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"Yalnız prioritet"</string>
- <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Yalnız alarmlar"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Narahat etməyin"</string>
+ <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"İcazəli şəxslər"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Bildirişlər"</string>
<string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"Tam sakitlik"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Cihaz)"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Daxiletmə metodu"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Yer"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Yer Deaktiv"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Kameranı bloklayın"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mikrofonu səssiz edin"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraya giriş"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofona giriş"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Əlçatan"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloklanmış"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media cihazı"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Yalnız təcili zənglər"</string>
@@ -386,10 +394,10 @@
<string name="quick_settings_connected" msgid="3873605509184830379">"Qoşulu"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Qoşuldu, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya"</string>
<string name="quick_settings_connecting" msgid="2381969772953268809">"Qoşulur..."</string>
- <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Birləşmə"</string>
+ <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Modem rejimi"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Aktiv edilir..."</string>
- <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Data Qənaəti aktivdir"</string>
+ <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Trafikə qənaət edilir"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
<item quantity="other">%d cihaz</item>
<item quantity="one">%d cihaz</item>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekran yazması"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlayın"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dayandırın"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Davam etmək üçün <b><xliff:g id="APP">%s</xliff:g></b> tətbiqi cihazın mikrofonuna giriş tələb edir."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Davam etmək üçün <b><xliff:g id="APP">%s</xliff:g></b> tətbiqi cihazın kamerasına giriş tələb edir."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonu blokdan çıxarılsın?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerası blokdan çıxarılsın?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası və mikrofonu blokdan çıxarılsın?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Bu, mikrofonunuzdan istifadə etməyə icazə verilən bütün tətbiq və xidmətlər üçün girişi blokdan çıxarır."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Bu, kameranızdan istifadə etməyə icazə verilən bütün tətbiq və xidmətlər üçün girişi blokdan çıxarır."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Bu, kamera və ya mikrofonunuzdan istifadə etməyə icazə verilən bütün tətbiq və xidmətlər üçün girişi blokdan çıxarır."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Tətbiqi dəyişmək üçün yuxarı sürüşdürün"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tətbiqləri cəld dəyişmək üçün sağa çəkin"</string>
@@ -455,8 +467,8 @@
<string name="camera_hint" msgid="4519495795000658637">"Kamera üçün ikonadan sürüşdürün"</string>
<string name="interruption_level_none_with_warning" msgid="8394434073508145437">"Ümumi sakitlik. Bu, ekran oxucularını da susduracaq."</string>
<string name="interruption_level_none" msgid="219484038314193379">"Tam sakitlik"</string>
- <string name="interruption_level_priority" msgid="661294280016622209">"Yalnız prioritet"</string>
- <string name="interruption_level_alarms" msgid="2457850481335846959">"Yalnız alarmlar"</string>
+ <string name="interruption_level_priority" msgid="661294280016622209">"İcazəli şəxslər"</string>
+ <string name="interruption_level_alarms" msgid="2457850481335846959">"Bildirişlər"</string>
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"Tam\nsakitlik"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Yalnız\nprioritet"</string>
<string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Yalnız\nalarmlar"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Zəngli saat"</string>
<string name="wallet_title" msgid="5369767670735827105">"Pulqabı"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Hazır"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Ödəniş kartı ayarlayın"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"İstifadə etmək üçün kiliddən çıxarın"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Kartların əldə edilməsində problem oldu, sonra yenidən cəhd edin"</string>
<string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Təyyarə rejimi"</string>
<string name="add_tile" msgid="6239678623873086686">"Xana əlavə edin"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Səssiz rejimə keçirilib"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> Yuxarı sıraya keçirilib"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> Aşağı sıraya keçirilib"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Prioritet rejimi aktiv olsa da, həmişə bildirişlərinizin yuxarı hissəsində göstərilir"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioritet söhbətlər"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbət funksiyalarını dəstəkləmir"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildiriş qrupunu burada konfiqurasiya etmək olmaz"</string>
@@ -850,9 +856,9 @@
<string name="accessibility_long_click_tile" msgid="210472753156768705">"Ayarları açın"</string>
<string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"Qulaqlıq qoşulub"</string>
<string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Qulaqlıq qoşulub"</string>
- <string name="data_saver" msgid="3484013368530820763">"Data Qənaəti"</string>
- <string name="accessibility_data_saver_on" msgid="5394743820189757731">"Data Qənaəti aktivdir"</string>
- <string name="accessibility_data_saver_off" msgid="58339669022107171">"Data Qənaəti deaktivdir"</string>
+ <string name="data_saver" msgid="3484013368530820763">"Trafikə qənaət"</string>
+ <string name="accessibility_data_saver_on" msgid="5394743820189757731">"Trafikə qənaət edilir"</string>
+ <string name="accessibility_data_saver_off" msgid="58339669022107171">"Trafikə qənaət edilmir"</string>
<string name="switch_bar_on" msgid="1770868129120096114">"Aktiv"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Deaktiv"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Əlçatan deyil"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistem naviqasiyasını yeniləmək üçün Ayarlara keçin"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Söhbət prioritet olaraq ayarlanıb"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioritet söhbətlər"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Bu söhbətlər siyahınızın yuxarı hissəsində göstərilir və Prioritet rejimi aktiv olduqda hər zaman sizə çata bilər"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profil şəkilləri kilid ekranında göstərilir"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Bu danışıqları Əsas ekranda yumrucuqlarda asanlıqla tapa bilərsiniz"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Narahat Etməyin rejimində göstərilsin"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Anladım"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ayarlar"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Dəyişdirici"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Əlçatımlılıq düyməsi əlçatımlılıq jestini əvəz etdi\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düyməni müvəqqəti gizlətmək üçün kənara çəkin"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuxarıya sola köçürün"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuxarıya sağa köçürün"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Aşağıya sola köçürün"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Aşağıya sağa köçürün"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"İçəri keçirib gizlədin"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kənara daşıyıb göstərin"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Cihaz idarəetmələri"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Qoşulmuş cihazlarınız üçün nizamlayıcılar əlavə edin"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz idarəetmələrini ayarlayın"</string>
@@ -1116,7 +1112,7 @@
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> cihaz seçilib"</string>
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (bağlantı kəsilib)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Qoşulmaq alınmadı. Yenə cəhd edin."</string>
- <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihazı qoşalaşdırın"</string>
+ <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Cihaz əlavə edin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versiya nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Maksimum <xliff:g id="DURATION">%1$s</xliff:g> əvvəl"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Minimum <xliff:g id="DURATION">%1$s</xliff:g> əvvəl"</string>
<string name="birthday_status" msgid="2596961629465396761">"Doğum günü"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> adlı şəxsin doğum günüdür"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Tezliklə doğum günü"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Tezliklə <xliff:g id="NAME">%1$s</xliff:g> adlı şəxsin doğum günüdür"</string>
<string name="anniversary_status" msgid="1790034157507590838">"İldönümü"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> adlı şəxsin ildönümüdür"</string>
<string name="location_status" msgid="1294990572202541812">"Məkan paylaşılır"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> məkanı paylaşır"</string>
<string name="new_story_status" msgid="9012195158584846525">"Yeni hekayə"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> yeni hekayə paylaşıb"</string>
<string name="video_status" msgid="4548544654316843225">"Baxır"</string>
<string name="audio_status" msgid="4237055636967709208">"Dinlənilir"</string>
<string name="game_status" msgid="1340694320630973259">"Oxudulur"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Dostlar"</string>
<string name="empty_status" msgid="5938893404951307749">"Bugün söhbət edək!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Məzmun tezliklə görünəcək"</string>
<string name="missed_call" msgid="4228016077700161689">"Buraxılmış zəng"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Son mesajlar, buraxılmış zənglər və status güncəlləmələrinə baxın"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Söhbət"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> mesaj göndərdi"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> şəkil göndərdi"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya ölçüsünü oxuyarkən problem yarandı"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ətraflı məlumat üçün toxunun"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Siqnal ayarlanmayıb"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 3feaa20..b03ca1f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimite još"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Gornja granica"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Donja granica"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
@@ -123,7 +129,7 @@
<string name="usb_preference_title" msgid="1439924437558480718">"Opcije USB prenosa datoteka"</string>
<string name="use_mtp_button_title" msgid="5036082897886518086">"Priključi kao medija plejer (MTP)"</string>
<string name="use_ptp_button_title" msgid="7676427598943446826">"Priključi kao kameru (PTP)"</string>
- <string name="installer_cd_button_title" msgid="5499998592841984743">"Instaliraj Android prebacivanje datoteka za Mac"</string>
+ <string name="installer_cd_button_title" msgid="5499998592841984743">"Instaliraj Android prebacivanje fajlova za Mac"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Nazad"</string>
<string name="accessibility_home" msgid="5430449841237966217">"Početna"</string>
<string name="accessibility_menu" msgid="2701163794470513040">"Meni"</string>
@@ -350,8 +356,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metod unosa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokacija je isključena"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokiraj kameru"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Isključi mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup kameri"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokirano"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijski uređaj"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Samo hitni pozivi"</string>
@@ -424,8 +432,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snimak ekrana"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Počnite"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"<b><xliff:g id="APP">%s</xliff:g></b> zahteva pristup mikrofonu uređaja radi nastavljanja."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"<b><xliff:g id="APP">%s</xliff:g></b> zahteva pristup kameri uređaja radi nastavljanja."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite da odblokirate mikrofon uređaja?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite da odblokirate kameru uređaja?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite da odblokirate kameru i mikrofon uređaja?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje mikrofona."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje kamere."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ovim će se odblokirati pristup za sve aplikacije i usluge koje imaju dozvolu za korišćenje kamere ili mikrofona."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Prevucite nagore da biste menjali aplikacije"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Prevucite udesno da biste brzo promenili aplikacije"</string>
@@ -660,18 +672,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Eternet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Spremno"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Podesite plaćanje"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključaj radi korišćenja"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema pri preuzimanju kartica. Probajte ponovo kasnije"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Režim rada u avionu"</string>
<string name="add_tile" msgid="6239678623873086686">"Dodaj pločicu"</string>
@@ -740,11 +748,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Degradirano u Nečujno"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> Rangirano više"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> Rangirano niže"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Uvek se prikazuje u vrhu obaveštenja čak i kada je Prioritetni režim uključen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Podešavanja"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioritetne konverzacije"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ova grupa obaveštenja ne može da se konfiguriše ovde"</string>
@@ -1020,14 +1026,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Podešavanja da biste ažurirali navigaciju sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Konverzacija je podešena na prioritetnu"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioritetne konverzacije"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ove konverzacije se prikazuju u vrhu liste i uvek mogu da dopru do vas kada je Prioritetni režim uključen"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Slike profila se prikazuju na zaključanom ekranu"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Lako možete da pronađete ove konverzacije u oblačićima na početnom ekranu"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ometa podešavanje Ne uznemiravaj"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Važi"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Podešavanja"</string>
@@ -1045,18 +1047,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pređi"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Dugme Pristupačnost je zamenilo pokret za pristupačnost\n\n"<annotation id="link">"Prikaži podešavanja"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomerite dugme do ivice da biste ga privremeno sakrili"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premesti gore levo"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premesti gore desno"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Premesti dole levo"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premesti dole desno"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premesti do ivice i sakrij"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premesti izvan ivice i prikaži"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Podesite kontrole uređaja"</string>
@@ -1136,35 +1132,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Pre manje od <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Pre više od <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rođendan"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> danas slavi rođendan"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rođendan je uskoro"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> uskoro slavi rođendan"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Godišnjica"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> danas slavi godišnjicu"</string>
<string name="location_status" msgid="1294990572202541812">"Deli se lokacija"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> deli lokaciju"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nova priča"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> deli novu priču"</string>
<string name="video_status" msgid="4548544654316843225">"Gleda se"</string>
<string name="audio_status" msgid="4237055636967709208">"Sluša se"</string>
<string name="game_status" msgid="1340694320630973259">"Igra se"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Prijatelji"</string>
<string name="empty_status" msgid="5938893404951307749">"Ćaskamo večeras!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Sadržaj će se uskoro pojaviti"</string>
<string name="missed_call" msgid="4228016077700161689">"Propušten poziv"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pogledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzacija"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> šalje poruku"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> šalje sliku"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem sa očitavanjem merača baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm nije podešen"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 51c67a1..2d078fc 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -57,12 +57,12 @@
<string name="label_view" msgid="6815442985276363364">"Прагляд"</string>
<string name="always_use_device" msgid="210535878779644679">"Заўсёды адкрываць <xliff:g id="APPLICATION">%1$s</xliff:g>, калі падключана прылада <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"Заўсёды адкрываць <xliff:g id="APPLICATION">%1$s</xliff:g>, калі падключаны аксесуар <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
- <string name="usb_debugging_title" msgid="8274884945238642726">"Дазволіць адладку USB?"</string>
+ <string name="usb_debugging_title" msgid="8274884945238642726">"Дазволіць адладку па USB?"</string>
<string name="usb_debugging_message" msgid="5794616114463921773">"Адбiтак ключа RSA на гэтым камп\'ютары:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="4003121804294739548">"Заўсёды дазваляць з гэтага камп\'ютара"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"Дазволіць"</string>
- <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Адладка USB не дапускаецца"</string>
- <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Карыстальнік, які зараз увайшоў у гэту прыладу, не можа ўключыць адладку USB. Каб выкарыстоўваць гэту функцыю, пераключыцеся на асноўнага карыстальніка."</string>
+ <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Адладка па USB забаронена"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Карыстальнік, які зараз увайшоў у гэту прыладу, не можа ўключыць адладку па USB. Каб выкарыстоўваць гэту функцыю, пераключыцеся на асноўнага карыстальніка."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Дазволіць адладку па Wi-Fi у гэтай сетцы?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Назва сеткі (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдрас Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"Заўсёды дазваляць у гэтай сетцы"</string>
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Зняць больш"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Адхіліць здымак экрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Перадпрагляд здымка экрана"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Верхняя граніца"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Ніжняя граніца"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Запіс экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Апрацоўваецца запіс экрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Метад уводу"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Месцазнаходжанне"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Вызначэнне месцазнаходжання адключана"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Заблакіраваць камеру"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Адключыць мікрафон"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ да камеры"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ да мікрафона"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступ дазволены"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Няма доступу"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Мультымедыйная прылада"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Толькі экстранныя выклікі"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запіс экрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Пачаць"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Спыніць"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Каб працягнуць, дайце праграме <b><xliff:g id="APP">%s</xliff:g></b> доступ да мікрафона прылады."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Каб працягнуць, дайце праграме <b><xliff:g id="APP">%s</xliff:g></b> доступ да камеры прылады."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблакіраваць мікрафон прылады?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблакіраваць камеру прылады?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблакіраваць камеру і мікрафон прылады?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць мікрафон."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць камеру."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Доступ адкрыецца для ўсіх праграм і сэрвісаў, якім дазволена выкарыстоўваць камеру ці мікрафон."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Прылада"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Правядзіце ўверх, каб пераключыць праграмы"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Каб хутка пераключыцца паміж праграмамі, перацягніце ўправа"</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Будзільнік"</string>
<string name="wallet_title" msgid="5369767670735827105">"Кашалёк"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Гатова"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Наладзіць спосаб аплаты"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблакіраваць для выкарыстання"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Узнікла праблема з загрузкай вашых карт. Паўтарыце спробу пазней"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Працоўны профіль"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Рэжым палёту"</string>
<string name="add_tile" msgid="6239678623873086686">"Дадаць плітку"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Стан:</b> Пераведзена ў рэжым \"Без гуку\""</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Стан:</b> Ацэнена як важнае"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Стан:</b> Ацэнена як няважнае"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Заўсёды паказваюцца над вашымі апавяшчэннямі, нават калі ўключаны прыярытэтны рэжым"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налады"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Прыярытэтныя размовы"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Тут канфігурыраваць гэту групу апавяшчэнняў забаронена"</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перайдзіце ў Налады, каб абнавіць параметры навігацыі ў сістэме"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Размова пазначана як прыярытэтная"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Прыярытэтныя размовы"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Гэтыя размовы паказваюцца ўверсе вашага спіса, і вы можаце заўсёды бачыць іх, калі ўключаны прыярытэтны рэжым"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Відарысы профілю паказваюцца на экране блакіроўкі"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Вы можаце лёгка знайсці гэтыя размовы ва ўсплывальных апавяшчэннях на галоўным экране"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Паказваюцца ў рэжыме \"Не турбаваць\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Зразумела"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Налады"</string>
@@ -1050,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Каб часова схаваць кнопку, перамясціце яе на край"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перамясціць лявей і вышэй"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перамясціць правей і вышэй"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Перамясціць лявей і ніжэй"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Перамясціць правей і ніжэй"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перамясціць на край і схаваць"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перамясціць за край і паказаць"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Элементы кіравання прыладай"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Дадайце элементы кіравання для падключаных прылад"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Наладзіць элементы кіравання прыладай"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Менш за <xliff:g id="DURATION">%1$s</xliff:g> таму"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Больш за <xliff:g id="DURATION">%1$s</xliff:g> таму"</string>
<string name="birthday_status" msgid="2596961629465396761">"Дзень нараджэння"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> святкуе дзень нараджэння"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Хутка свята"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Неўзабаве <xliff:g id="NAME">%1$s</xliff:g> святкуе дзень нараджэння"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Гадавіна"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> адзначае юбілей"</string>
<string name="location_status" msgid="1294990572202541812">"Абагульваецца месца"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> абагульвае геаданыя"</string>
<string name="new_story_status" msgid="9012195158584846525">"Новая гісторыя"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> абагуліў новую гісторыю"</string>
<string name="video_status" msgid="4548544654316843225">"Ідзе прагляд відэа"</string>
<string name="audio_status" msgid="4237055636967709208">"Гаварыце"</string>
<string name="game_status" msgid="1340694320630973259">"Ідзе гульня"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Сябры"</string>
<string name="empty_status" msgid="5938893404951307749">"Паразмаўляем у чаце!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Неўзабаве з\'явіцца змесціва"</string>
<string name="missed_call" msgid="4228016077700161689">"Прапушчаны выклік"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Глядзець нядаўнія паведамленні, прапушчаныя выклікі і абнаўленні стану"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Размова"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> адправіў паведамленне"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> адправіў відарыс"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Праблема з чытаннем індыкатара зараду акумулятара"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Націсніце, каб убачыць больш"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма будзільнікаў"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bf8aaad..3ccb318 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Заснемане на още"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Отхвърляне на екранната снимка"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Визуализация на екранната снимка"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Горна граница"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Долна граница"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Запис на екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод на въвеждане"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Местоположението е изключено"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Блокиране на камерата"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Спиране на микрофона"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Достъп до камерата"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Достъп до микрофона"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Налице"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Блокирано"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Мултимедийно устройство"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"Индикатор за силата на получения сигнал (RSSI)"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Само спешни обаждания"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Записване на екрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Старт"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Стоп"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"За да продължите, <b><xliff:g id="APP">%s</xliff:g></b> се нуждае от достъп до микрофона на устройството ви."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"За да продължите, <b><xliff:g id="APP">%s</xliff:g></b> се нуждае от достъп до камерата на устройството ви."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се отблокира ли микрофонът на устройството?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се отблокира ли камерата на устройството?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се отблокират ли камерата и микрофонът на устройството?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват микрофона ви."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват камерата ви."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Това действие отблокира достъпа за всички приложения и услуги, които имат разрешение да използват камерата или микрофона ви."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Устройство"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Прекарайте пръст нагоре, за да превключите между приложенията"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Плъзнете надясно за бързо превключване между приложенията"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Будилник"</string>
<string name="wallet_title" msgid="5369767670735827105">"Портфейл"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Готово"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Настройване на плащане"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отключване с цел използване"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"При извличането на картите ви възникна проблем. Моля, опитайте отново по-късно"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Потребителски профил в Work"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Самолетен режим"</string>
<string name="add_tile" msgid="6239678623873086686">"Добавяне на плочка"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Състояние:</b> Понижено до беззвучно"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Състояние:</b> Класирано по-високо"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Състояние:</b> Класирано по-ниско"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Винаги се показва най-горе в списъка с известия дори когато режимът за приоритетни разговори е включен"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Разговори с приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Тази група от известия не може да бъде конфигурирана тук"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Отворете настройките, за да актуализирате режима за навигиране в системата"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Разговорът е зададен като приоритетен"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Разговори с приоритет"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Тези разговори се показват най-горе в списъка ви и винаги ще стигат до вас, когато приоритетният режим е включен"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Снимките на потребителските профили се показват на заключения екран"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Лесно можете да намерите тези разговори под формата на балончета на началния екран"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Прекъсване на режима „Не безпокойте“"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Разбрах"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Настройки"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Преместете бутона до края, за да го скриете временно"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Преместване горе вляво"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Преместване горе вдясно"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Преместване долу вляво"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Преместване долу вдясно"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Преместване в края и скриване"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Преместване в края и показване"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавяне на контроли за свързаните ви устройства"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройване на контролите за устройството"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Преди по-малко от <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Преди повече от <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Рожден ден"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Днес е рожденият ден на <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Предстоящ рожден ден"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Скоро е рожденият ден на <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Годишнина"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Днес е годишнината на <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Местопол. се споделя"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> споделя местоположението си"</string>
<string name="new_story_status" msgid="9012195158584846525">"Нова история"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> сподели нова история"</string>
<string name="video_status" msgid="4548544654316843225">"Гледате"</string>
<string name="audio_status" msgid="4237055636967709208">"Слуша се"</string>
<string name="game_status" msgid="1340694320630973259">"Играете"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Приятели"</string>
<string name="empty_status" msgid="5938893404951307749">"Да разговаряме!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Съдържанието ще се покаже скоро"</string>
<string name="missed_call" msgid="4228016077700161689">"Пропуснато обаждане"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Над <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Преглеждайте скорошните съобщения, пропуснатите обаждания и актуална информация за състоянието"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> изпрати съобщение"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> изпрати изображение"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Възникна проблем при четенето на данните за нивото на батерията"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Докоснете за още информация"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Няма зададен будилник"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index a13381f..be162f8 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"আরও বেশি ক্যাপচার করুন"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্রিনশট বাতিল করুন"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্রিনশটের প্রিভিউ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"স্ক্রিনশটের একদম উপরের দিকে"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"স্ক্রিনশটের একদম নিচের দিকে"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্রিন রেকর্ডার"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ইনপুট পদ্ধতি"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"লোকেশন"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"লোকেশন বন্ধ করা আছে"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ক্যামেরা ব্লক করুন"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"মাইক্রোফোন মিউট করুন"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"মিডিয়া ডিভাইস"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"শুধুমাত্র জরুরি কল"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"স্ক্রিন রেকর্ড"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"শুরু করুন"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ করুন"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"চালিয়ে যেতে, <b><xliff:g id="APP">%s</xliff:g></b> আপনার ডিভাইসের মাইক্রোফোন অ্যাক্সেস করতে চায়।"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"চালিয়ে যেতে, <b><xliff:g id="APP">%s</xliff:g></b> আপনার ডিভাইসের ক্যামেরা অ্যাক্সেস করতে চায়।"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"ডিভাইস"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"অন্য অ্যাপে যেতে উপরের দিকে সোয়াইপ করুন"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"একটি অ্যাপ ছেড়ে দ্রুত অন্য অ্যাপে যেতে ডান দিকে টেনে আনুন"</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ইথারনেট"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"অ্যালার্ম"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"রেডি"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"পেমেন্ট সেট আপ করুন"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string>
<string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string>
<string name="add_tile" msgid="6239678623873086686">"টাইল যোগ করুন"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>স্ট্যাটাস:</b> লেভেল কমিয়ে সাইলেন্ করা হয়েছে"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>স্ট্যাটাস:</b> র্যাঙ্ক বেড়ে গেছে"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>স্ট্যাটাস:</b> র্যাঙ্ক কমে গেছে"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"এমনকি \'অগ্রাধিকার\' মোড চালু থাকলেও এটি সব সময় আপনার বিজ্ঞপ্তির উপরে দেখা যায়"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"সেটিংস"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"গুরুত্বপূর্ণ কথোপকথন"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"এই সমস্ত বিজ্ঞপ্তিকে এখানে কনফিগার করা যাবে না"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"কথোপকথনকে \'গুরুত্বপূর্ণ\' হিসেবে সেট করা হয়েছে"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"গুরুত্বপূর্ণ কথোপকথন"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"এই কথোপকথনগুলি আপনার তালিকার একেবারে উপরে দেখা যায় এবং \'অগ্রাধিকার\' মোড চালু থাকলে সব সময় আপনি সেগুলি পড়তে পারেন"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"প্রোফাইল ছবি লক স্ক্রিনে দেখা যায়"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"আপনার হোম স্ক্রিনের বাবলে সহজেই এই গুরুত্বপূর্ণ কথোপকথনগুলি দেখতে পাবেন"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"বিরক্ত করবে না মোডে ব্যাঘাত ঘটাতে পারে"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"বুঝেছি"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"সেটিংস"</string>
@@ -1040,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"এটি অস্থায়ীভাবে লুকাতে বোতামটি কোণে সরান"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"উপরে বাঁদিকে সরান"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"উপরে ডানদিকে সরান"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"নিচে বাঁদিকে সরান"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"নিচে ডান দিকে সরান"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"প্রান্তে যান ও আড়াল করুন"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"প্রান্ত থেকে সরান এবং দেখুন"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইস কন্ট্রোল"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"আপনার কানেক্ট করা ডিভাইসের জন্য কন্ট্রোল যোগ করুন"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইস কন্ট্রোল সেট-আপ করুন"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> থেকে কিছু কম সময় আগে"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> সপ্তাহেরও আগে"</string>
<string name="birthday_status" msgid="2596961629465396761">"জন্মদিন"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g>-এর জন্মদিন"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"জন্মদিন শীঘ্রই আসছে"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g>-এর জন্মদিন খুব শীঘ্র আসছে"</string>
<string name="anniversary_status" msgid="1790034157507590838">"বার্ষিকী"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g>-এর বার্ষিকী"</string>
<string name="location_status" msgid="1294990572202541812">"লোকেশন শেয়ার করা হচ্ছে"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> লোকেশন শেয়ার করছেন"</string>
<string name="new_story_status" msgid="9012195158584846525">"নতুন খবর"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> একটি নতুন খবর শেয়ার করেছেন"</string>
<string name="video_status" msgid="4548544654316843225">"দেখছি"</string>
<string name="audio_status" msgid="4237055636967709208">"অডিও শুনছি"</string>
<string name="game_status" msgid="1340694320630973259">"চালানো হচ্ছে"</string>
<string name="empty_user_name" msgid="3389155775773578300">"বন্ধু"</string>
<string name="empty_status" msgid="5938893404951307749">"আজ রাতে চ্যাট করা যাক!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"কন্টেন্ট খুব শীঘ্র দেখা যাবে"</string>
<string name="missed_call" msgid="4228016077700161689">"মিসড কল"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"সাম্প্রতিক মেসেজ, মিসড কল এবং স্ট্যাটাস সংক্রান্ত আপডেট দেখুন"</string>
<string name="people_tile_title" msgid="6589377493334871272">"কথোপকথন"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> একটি মেসেজ পাঠিয়েছেন"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> একটি ছবি পাঠিয়েছেন"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ব্যাটারির মিটারের রিডিং নেওয়ার সময় সমস্যা হয়েছে"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"আরও তথ্যের জন্য ট্যাপ করুন"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"কোনও অ্যালার্ম সেট করা নেই"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4c5e917..12a1230 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimite više"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Gornja granica"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Donja granica"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
@@ -121,7 +127,7 @@
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dobijanje odobrenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
<string name="usb_preference_title" msgid="1439924437558480718">"Opcije USB prijenosa fajlova"</string>
- <string name="use_mtp_button_title" msgid="5036082897886518086">"Reproduciranje medijskih sadržaja (MTP)"</string>
+ <string name="use_mtp_button_title" msgid="5036082897886518086">"Učitaj kao plejer medija (MTP)"</string>
<string name="use_ptp_button_title" msgid="7676427598943446826">"Priključiti kao kameru (PTP)"</string>
<string name="installer_cd_button_title" msgid="5499998592841984743">"Instalirajte Android File Transfer za Mac"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Nazad"</string>
@@ -350,8 +356,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Način unosa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Utvrđivanje lokacije isključeno"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokirajte kameru"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Isključite mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup kameri"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokirano"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijski uređaj"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Samo pozivi za hitne slučajeve"</string>
@@ -424,8 +432,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snimanje ekrana"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Započnite"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Da nastavite, aplikaciji <b><xliff:g id="APP">%s</xliff:g></b> je potreban pristup mikrofonu vašeg uređaja."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Da nastavite, aplikaciji <b><xliff:g id="APP">%s</xliff:g></b> je potreban pristup kameri vašeg uređaja."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokirati mikrofon uređaja?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokirati kameru uređaja?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokirati kameru i mikrofon uređaja?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vaš mikrofon."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vašu kameru."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ovim se deblokira pristup za sve aplikacije i usluge kojima je dozvoljeno da koriste vašu kameru ili mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Prevucite prema gore za promjenu aplikacije"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Prevucite udesno za brzu promjenu aplikacija"</string>
@@ -660,18 +672,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Spremno"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Postavite način plaćanja"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da koristite"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema prilikom preuzimanja vaših kartica. Pokušajte ponovo kasnije"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil za posao"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string>
<string name="add_tile" msgid="6239678623873086686">"Dodaj pločicu"</string>
@@ -740,11 +748,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> je unazađen u Nečujno"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> je rangiran više"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> je rangiran niže"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Uvijek se prikazuje na vrhu obavještenja, čak i kada je uključen način rada Prioriteti"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioritetni razgovori"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ovu grupu obavještenja nije moguće konfigurirati ovdje"</string>
@@ -1020,14 +1026,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Postavke da ažurirate navigiranje sistemom"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Razgovor je postavljen kao prioritetan"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioritetni razgovori"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ti razgovori se prikazuju na vrhu liste i uvijek ih možete vidjeti kada je uključen način rada Prioriteti"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Slike profila se prikazuju na zaključanom ekranu"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"S lakoćom možete pronaći te razgovore u oblačićima na Početnom ekranu"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Prekida način rada Ne ometaj"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Razumijem"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Postavke"</string>
@@ -1045,18 +1047,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prekidač"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Dugme za pristupačnost je zamijenilo pokret za pristupačnost\n\n"<annotation id="link">"Prikaži postavke"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Premjestite dugme do ivice da ga privremeno sakrijete"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pomjeranje gore lijevo"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pomjeranje gore desno"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Pomjeranje dolje lijevo"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Pomjeranje dolje desno"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pomjeranje do ivice i sakrivanje"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pomjeranje izvan ivice i prikaz"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavite kontrole uređaja"</string>
@@ -1136,35 +1132,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Prije manje od <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Prije više od <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rođendan"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> slavi rođendan"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rođendan je uskoro"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> uskoro slavi rođendan"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Godišnjica"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> slavi godišnjicu"</string>
<string name="location_status" msgid="1294990572202541812">"Dijeljenje lokacije"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> dijeli lokaciju"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nova priča"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> je podijelio/la novu priču"</string>
<string name="video_status" msgid="4548544654316843225">"Gleda"</string>
<string name="audio_status" msgid="4237055636967709208">"Slušanje"</string>
<string name="game_status" msgid="1340694320630973259">"Reproduciranje"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Prijatelji"</string>
<string name="empty_status" msgid="5938893404951307749">"Chatajmo večeras!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Sadržaj će se uskoro prikazati"</string>
<string name="missed_call" msgid="4228016077700161689">"Propušteni poziv"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pregledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Razgovor"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la sliku"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Došlo je do problema prilikom očitavanja mjerača stanja baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nije postavljen alarm"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 032986c..2208ed1 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Captura més"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora la captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Previsualització de la captura de pantalla"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Marge superior"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Marge inferior"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Gravació de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Mètode d\'introducció"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicació desactivada"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloqueja la càmera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Silencia el micròfon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accés a la càmera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Accés al micròfon"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloquejat"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositiu multimèdia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Només trucades d\'emergència"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravació de pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inicia"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Atura"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Per continuar, <b><xliff:g id="APP">%s</xliff:g></b> necessita accedir al micròfon del dispositiu."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Per continuar, <b><xliff:g id="APP">%s</xliff:g></b> necessita accedir a la càmera del dispositiu."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vols desbloquejar el micròfon del dispositiu?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vols desbloquejar la càmera del dispositiu?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vols desbloquejar la càmera i el micròfon del dispositiu?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar el micròfon."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar la càmera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Aquesta opció desbloqueja l\'accés de tots els serveis i aplicacions que tenen permís per utilitzar la càmera o el micròfon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositiu"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Llisca cap amunt per canviar d\'aplicació"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrossega el dit cap a la dreta per canviar ràpidament d\'aplicació"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Preparat"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configura un pagament"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloqueja per utilitzar"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Hi ha hagut un problema en obtenir les teves targetes; torna-ho a provar més tard"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de treball"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode d\'avió"</string>
<string name="add_tile" msgid="6239678623873086686">"Afegeix un mosaic"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estat</b>: s\'ha disminuït a Silenci"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Estat</b>: s\'ha classificat amb un nivell superior"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Estat</b>: s\'ha classificat amb un nivell inferior"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Mostra sempre a la part superior de la llista de notificacions, fins i tot quan el mode Prioritat està activat"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuració"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Converses prioritàries"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquest grup de notificacions no es pot configurar aquí"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ves a Configuració per actualitzar el sistema de navegació"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"La conversa s\'ha definit com a prioritària"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Converses prioritàries"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Aquestes converses es mostren a la part superior de la llista i les pots rebre sempre amb el mode Prioritat activat"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Les fotos de perfil es mostren a la pantalla de bloqueig"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Pots trobar fàcilment aquestes converses a les bombolles de la pantalla d\'inici"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interromp el mode No molestis"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entesos"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuració"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Canvia"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El gest d\'accessibilitat s\'ha substituït pel botó d\'accessibilitat\n\n"<annotation id="link">"Mostra la configuració"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mou el botó a l\'extrem per amagar-lo temporalment"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mou a dalt a l\'esquerra"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mou a dalt a la dreta"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mou a baix a l\'esquerra"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mou a baix a la dreta"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mou dins de les vores i amaga"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mou fora de les vores i mostra"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Afegeix controls per als teus dispositius connectats"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura els controls de dispositius"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Fa menys de: <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Fa més de: <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversari"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Avui <xliff:g id="NAME">%1$s</xliff:g> fa anys"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversari aviat"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Aviat serà l\'aniversari de: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Aniversari"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"És l\'aniversari de: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Compartint la ubicació"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> està compartint la ubicació"</string>
<string name="new_story_status" msgid="9012195158584846525">"Història nova"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ha compartit una història nova"</string>
<string name="video_status" msgid="4548544654316843225">"Mirant"</string>
<string name="audio_status" msgid="4237055636967709208">"Escoltant"</string>
<string name="game_status" msgid="1340694320630973259">"Jugant"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amics"</string>
<string name="empty_status" msgid="5938893404951307749">"Parlem aquesta nit!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"El contingut es mostrarà aviat"</string>
<string name="missed_call" msgid="4228016077700161689">"Trucada perduda"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta els missatges recents, les trucades perdudes i les actualitzacions d\'estat"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat un missatge"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat una imatge"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Hi ha hagut un problema en llegir el mesurador de la bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca per obtenir més informació"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Cap alarma configurada"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c22fffd..0e11899 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Zachytit více"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavřít snímek obrazovky"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Náhled snímku obrazovky"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Horní hranice"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Dolní hranice"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metoda zadávání dat"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Poloha vypnuta"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokovat fotoaparát"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Vypnout mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Přístup k fotoaparátu"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Přístup k mikrofonu"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupné"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokováno"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediální zařízení"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Pouze tísňová volání"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Záznam obrazovky"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Spustit"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončit"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Než budete pokračovat, udělte aplikaci <b><xliff:g id="APP">%s</xliff:g></b> přístup k mikrofonu na zařízení."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Než budete pokračovat, udělte aplikaci <b><xliff:g id="APP">%s</xliff:g></b> přístup k fotoaparátu na zařízení."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokovat mikrofon zařízení?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokovat fotoaparát zařízení?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokovat fotoaparát a mikrofon zařízení?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš mikrofon."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš fotoaparát."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tímto odblokujete přístup všem aplikacím a službám, které mají povoleno používat váš fotoaparát či mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Zařízení"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Přejetím nahoru přepnete aplikace"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Přetažením doprava rychle přepnete aplikace"</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Budík"</string>
<string name="wallet_title" msgid="5369767670735827105">"Peněženka"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Připraveno"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Nastavit platbu"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odemknout a použít"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Při načítání karet došlo k problému, zkuste to později"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Pracovní profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Režim Letadlo"</string>
<string name="add_tile" msgid="6239678623873086686">"Přidat dlaždici"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stav:</b> priorita snížena na Tiché"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Stav:</b> zařazeno výše"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Stav:</b> zařazeno níže"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Vždy se zobrazuje na začátku vašich oznámení (i když je zapnutý prioritní režim)"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavení"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioritní konverzace"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Tuto skupinu oznámení tady nelze nakonfigurovat"</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Přejděte do Nastavení a aktualizujte systémovou navigaci"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Konverzace byla nastavena jako prioritní"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioritní konverzace"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Tyto konverzace se zařazují na začátek seznamu, a když je zapnutý prioritní režim, mohou se vám vždy zobrazit"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Na obrazovce uzamčení se zobrazují profilové obrázky"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Tyto konverzace snadno najdete v bublinách na ploše"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Přerušit režim Nerušit"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Rozumím"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavení"</string>
@@ -1050,18 +1052,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Přepnout"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tlačítko přístupnosti bylo nahrazeno gestem přístupnosti\n\n"<annotation id="link">"Zobrazit nastavení"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Přesunutím tlačítka k okraji ho dočasně skryjete"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Přesunout vlevo nahoru"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Přesunout vpravo nahoru"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Přesunout vlevo dolů"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Přesunout vpravo dolů"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Přesunout k okraji a skrýt"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Přesunout okraj ven a zobrazit"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládání zařízení"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Přidejte ovládací prvky pro připojená zařízení"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavení ovládání zařízení"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Před méně než <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Před více než <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Narozeniny"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> má narozeniny"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Brzy má narozeniny"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> bude mít brzy narozeniny"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Výročí"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> má výročí"</string>
<string name="location_status" msgid="1294990572202541812">"Sdílí polohu"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> sdílí polohu"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nový příběh"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> sdílí nový příběh"</string>
<string name="video_status" msgid="4548544654316843225">"Sledování"</string>
<string name="audio_status" msgid="4237055636967709208">"Poslouchám"</string>
<string name="game_status" msgid="1340694320630973259">"Hraje"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Přátelé"</string>
<string name="empty_status" msgid="5938893404951307749">"Pojďme chatovat."</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Obsah se brzy zobrazí"</string>
<string name="missed_call" msgid="4228016077700161689">"Zmeškaný hovor"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Zobrazit poslední zprávy, zmeškané hovory a aktualizace stavu"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzace"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> posílá zprávu"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> posílá obrázek"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problém s načtením měřiče baterie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím zobrazíte další informace"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Budík nenastaven"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 59dd774..cdc52a7 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Medtag mere"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Luk screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning af screenshot"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Øverste kant"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Nederste kant"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skærmoptagelse"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skærmoptagelse"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Inputmetode"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Placering"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Placering fra"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloker kameraet"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Slå mikrofonen fra"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraadgang"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonadgang"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tilgængelig"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokeret"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medieenhed"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Kun nødopkald"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Optag skærm"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"<b><xliff:g id="APP">%s</xliff:g></b> skal have adgang til din enheds mikrofon, før den kan fortsætte."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"<b><xliff:g id="APP">%s</xliff:g></b> skal have adgang til din enheds kamera, før den kan fortsætte."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du fjerne blokeringen af enhedens mikrofone?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du fjerne blokeringen af enhedens kamera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du fjerne blokeringen af enhedens kamera og mikrofon?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge din mikrofon."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge dit kamera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dette fjerner adgangsblokeringen for alle apps og tjenester, der har tilladelse til at bruge dit kamera eller din mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Enhed"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Stryg opad for at skifte apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Træk til højre for hurtigt at skifte app"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Klar"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Konfigurer betalingsmetode"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås op for at bruge"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Dine kort kunne ikke hentes. Prøv igen senere."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string>
<string name="add_tile" msgid="6239678623873086686">"Tilføj et felt"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Angivet som Lydløs"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> Rangeret højere"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> Placeret lavere"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Vises altid øverst i dine notifikationer – også når tilstanden Prioritet er aktiveret"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Indstillinger"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioriterede samtaler"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Du kan ikke konfigurere denne gruppe notifikationer her"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Indstillinger for at opdatere systemnavigationen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Samtalen er angivet som prioriteret"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioriterede samtaler"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Disse samtaler vises øverst på din liste og kan altid ses af dig, når tilstanden Prioritet er aktiveret"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profilbilleder vises på låseskærmen"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Du kan nemt finde disse samtaler i bobler på din startskærm"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Afbryd Forstyr ikke"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Indstillinger"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Skift"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Knappen Hjælpefunktioner har erstattet bevægelsen for hjælpefunktioner\n\n"<annotation id="link">"Se indstillinger"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flyt knappen til kanten for at skjule den midlertidigt"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flyt op til venstre"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flyt op til højre"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Flyt ned til venstre"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flyt ned til højre"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flyt ud til kanten, og skjul"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flyt ud til kanten, og vis"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tilføj styring af dine tilsluttede enheder"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhedsstyring"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"For mindre end <xliff:g id="DURATION">%1$s</xliff:g> siden"</string>
<string name="over_timestamp" msgid="4765793502859358634">"For mere end <xliff:g id="DURATION">%1$s</xliff:g> siden"</string>
<string name="birthday_status" msgid="2596961629465396761">"Fødselsdag"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> har fødselsdag i dag"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Fødselsdag snart"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> har snart fødselsdag"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Årsdag"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> har jubilæum i dag"</string>
<string name="location_status" msgid="1294990572202541812">"Deler placering"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> deler sin placering"</string>
<string name="new_story_status" msgid="9012195158584846525">"Ny historie"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> har delt en ny historie"</string>
<string name="video_status" msgid="4548544654316843225">"Ser"</string>
<string name="audio_status" msgid="4237055636967709208">"Lytter"</string>
<string name="game_status" msgid="1340694320630973259">"Spiller"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Venner"</string>
<string name="empty_status" msgid="5938893404951307749">"Lad os chatte i aften!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Indhold dukker snart op"</string>
<string name="missed_call" msgid="4228016077700161689">"Ubesvaret opkald"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Se dine seneste beskeder, mistede opkald og statusopdateringer"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Samtale"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en sms"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et billede"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Der er problemer med at aflæse dit batteriniveau"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryk for at få flere oplysninger"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm er indstillet"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 7c590cf..6fe6658 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Mehr aufnehmen"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot schließen"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshotvorschau"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Oberer Rand"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Unterer Rand"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
@@ -259,8 +265,8 @@
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"lautlos"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"nur Weckrufe"</string>
<string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Nicht stören."</string>
- <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\"Bitte nicht stören\" deaktiviert."</string>
- <string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"\"Bitte nicht stören\" aktiviert"</string>
+ <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"„Bitte nicht stören“ deaktiviert."</string>
+ <string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"„Bitte nicht stören“ aktiviert"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"Bluetooth deaktiviert"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aktiviert"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Eingabemethode"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Standort"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Standort aus"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Kamera blockieren"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mikrofon stummschalten"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediengerät"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Nur Notrufe"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Bildschirmaufnahme"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Beenden"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Zum Fortfahren benötigt, <b><xliff:g id="APP">%s</xliff:g></b> Zugriff auf das Mikrofon deines Geräts."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Zum Fortfahren benötigt <b><xliff:g id="APP">%s</xliff:g></b> Zugriff auf die Kamera deines Geräts."</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"Gerät"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Nach oben wischen, um Apps zu wechseln"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Zum schnellen Wechseln der Apps nach rechts ziehen"</string>
@@ -497,7 +519,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduzierung der Leistung und Hintergrunddaten"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Energiesparmodus deaktivieren"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"Die App \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise angezeigte Passwörter und Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Der Anbieter dieser App erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise Passwörter, Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Der Anbieter dieser App erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise angezeigte Passwörter, Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Aufnahme oder Stream starten?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Aufnehmen oder Streamen mit der App \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" starten?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"Nicht mehr anzeigen"</string>
@@ -509,7 +531,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Benachrichtigungen"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Unterhaltungen"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle lautlosen Benachrichtigungen löschen"</string>
- <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Benachrichtigungen durch \"Bitte nicht stören\" pausiert"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Benachrichtigungen durch „Bitte nicht stören“ pausiert"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Jetzt starten"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Keine Benachrichtigungen"</string>
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil wird eventuell überwacht."</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Weckruf"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Bereit"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Zahlungsmethode einrichten"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Zum Verwenden entsperren"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Beim Abrufen deiner Karten ist ein Fehler aufgetreten – bitte versuch es später noch einmal"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Arbeitsprofil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flugmodus"</string>
<string name="add_tile" msgid="6239678623873086686">"Kachel hinzufügen"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status</b>: auf „Lautlos“ herabgestuft"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status</b>: höher eingestuft"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status</b>: niedriger eingestuft"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Werden immer in deinen Benachrichtigungen immer oben angezeigt, auch wenn der Prioritätsmodus aktiviert ist"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Einstellungen"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Vorrangige Unterhaltungen"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string>
@@ -843,7 +859,7 @@
<string name="tuner_full_zen_title" msgid="5120366354224404511">"Einschließlich Lautstärkeregler anzeigen"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"Bitte nicht stören"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Tastenkombination für Lautstärketasten"</string>
- <string name="volume_up_silent" msgid="1035180298885717790">"\"Bitte nicht stören\" bei \"Lauter\" deaktivieren"</string>
+ <string name="volume_up_silent" msgid="1035180298885717790">"„Bitte nicht stören“ bei \"Lauter\" deaktivieren"</string>
<string name="battery" msgid="769686279459897127">"Akku"</string>
<string name="clock" msgid="8978017607326790204">"Uhr"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -969,9 +985,9 @@
<string name="wifi_is_off" msgid="5389597396308001471">"WLAN ist deaktiviert"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ist deaktiviert"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"„Bitte nicht stören“ ist deaktiviert"</string>
- <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"\"Bitte nicht stören\" wurde von einer automatischen Regel aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
- <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"\"Bitte nicht stören\" wurde von einer App aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
- <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"\"Bitte nicht stören\" wurde von einer automatischen Regel oder einer App aktiviert."</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"„Bitte nicht stören“ wurde von einer automatischen Regel aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"„Bitte nicht stören“ wurde von einer App aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"„Bitte nicht stören“ wurde von einer automatischen Regel oder einer App aktiviert."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"Bis <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="qs_dnd_keep" msgid="3829697305432866434">"Beibehalten"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"Ersetzen"</string>
@@ -1015,15 +1031,11 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gehe zu den Einstellungen, um die Systemsteuerung anzupassen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Unterhaltung als vorrangig eingestuft"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
- <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\"Bitte nicht stören\" unterbrechen"</string>
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Vorrangige Unterhaltungen"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Unterhaltungen, bei denen der Prioritätsmodus an ist, werden auf der Liste oben angezeigt und kommen immer bei dir an"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profilbilder werden auf dem Sperrbildschirm angezeigt"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Diese Unterhaltungen kannst du in Bubbles auf deinem Startbildschirm sehen"</string>
+ <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"„Bitte nicht stören“ unterbrechen"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Einstellungen"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrößerungsfenster"</string>
@@ -1040,18 +1052,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schalter"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Die Schaltfläche „Bedienungshilfen“ ersetzt die Touch-Geste für Bedienungshilfen\n\n"<annotation id="link">"Einstellungen aufrufen"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Durch Ziehen an den Rand wird die Schaltfläche zeitweise ausgeblendet"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Nach oben links verschieben"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Nach rechts oben verschieben"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Nach unten links verschieben"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Nach unten rechts verschieben"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"An den Rand verschieben und verbergen"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Vom Rand verschieben und anzeigen"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Steuerelemente für verbundene Geräte hinzufügen"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Gerätesteuerung einrichten"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Vor weniger als <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Vor über <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Geburtstag"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> hat Geburtstag"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Bald Geburtstag"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> hat bald Geburtstag"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Jahrestag"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> hat heute Jahrestag"</string>
<string name="location_status" msgid="1294990572202541812">"Standort wird geteilt"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> teilt den Standort"</string>
<string name="new_story_status" msgid="9012195158584846525">"Neue Geschichte"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> hat eine neue Geschichte geteilt"</string>
<string name="video_status" msgid="4548544654316843225">"Schaut etwas"</string>
<string name="audio_status" msgid="4237055636967709208">"Hört etwas"</string>
<string name="game_status" msgid="1340694320630973259">"Spielt"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Freunde"</string>
<string name="empty_status" msgid="5938893404951307749">"Chat heute Abend!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Der Inhalt wird bald angezeigt"</string>
<string name="missed_call" msgid="4228016077700161689">"Verpasster Anruf"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Letzte Nachrichten, verpasste Anrufe und Statusaktualisierungen ansehen"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Unterhaltung"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> hat eine Nachricht gesendet"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> hat ein Bild gesendet"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem beim Lesen des Akkustands"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Für weitere Informationen tippen"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Kein Wecker gestellt"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 81cc35b..28e1b0e 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Λήψη περισσότερων"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Παράβλεψη στιγμιότυπου οθόνης"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Προεπισκόπηση στιγμιότυπου οθόνης"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Ανώτατο όριο"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Κατώτατο όριο"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Εγγραφή οθόνης"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ειδοποίηση σε εξέλιξη για μια περίοδο λειτουργίας εγγραφής οθόνης"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Μέθοδος εισαγωγής"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Τοποθεσία"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Τοποθεσία απενεργοποιημένη"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Αποκλεισμός Κάμερας"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Σίγαση μικροφώνου"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Πρόσβαση κάμερας"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Πρόσβαση μικροφώνου"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Διαθέσιμη"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Αποκλεισμένη"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Συσκευή μέσων"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Μόνο κλήσεις έκτακτης ανάγκης"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Εγγραφή οθόνης"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Έναρξη"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Διακοπή"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Για να συνεχίσετε, η εφαρμογή <b><xliff:g id="APP">%s</xliff:g></b&gt, χρειάζεται πρόσβαση στο μικρόφωνο της συσκευής σας."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Για να συνεχίσετε, η εφαρμογή <b><xliff:g id="APP">%s</xliff:g></b> χρειάζεται πρόσβαση στην κάμερα της συσκευής σας."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Κατάργηση αποκλεισμού μικροφώνου συσκευής;"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Κατάργηση αποκλεισμού κάμερας συσκευής;"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Κατάργηση αποκλεισμού κάμερας και μικροφώνου συσκευής;"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν το μικρόφωνό σας."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν την κάμερά σας."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Με αυτόν τον τρόπο καταργείται ο αποκλεισμός της πρόσβασης για όλες τις εφαρμογές και υπηρεσίες που επιτρέπεται να χρησιμοποιούν την κάμερα ή το μικρόφωνό σας."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Συσκευή"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Σύρετε προς τα επάνω για εναλλαγή των εφαρμογών"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Σύρετε προς τα δεξιά για γρήγορη εναλλαγή εφαρμογών"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Ξυπνητήρι"</string>
<string name="wallet_title" msgid="5369767670735827105">"Πορτοφόλι"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Έτοιμο"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Ρύθμιση πληρωμής"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ξεκλείδωμα για χρήση"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Παρουσιάστηκε πρόβλημα με τη λήψη των καρτών σας. Δοκιμάστε ξανά αργότερα"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Προφίλ εργασίας"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Λειτουργία πτήσης"</string>
<string name="add_tile" msgid="6239678623873086686">"Προσθήκη πλακιδίου"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Κατάσταση:</b> Υποβιβάστηκε σε Αθόρυβη"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Κατάσταση:</b> Κατατάχθηκε υψηλότερα"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Κατάσταση:</b> Κατατάχθηκε χαμηλότερα"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Εμφανίζεται πάντα στην κορυφή των ειδοποιήσεων, ακόμη και όταν η λειτουργία προτεραιότητας είναι ενεργοποιημένη"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ρυθμίσεις"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Συζητήσεις προτεραιότητας"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Δεν είναι δυνατή η διαμόρφωση αυτής της ομάδας ειδοποιήσεων εδώ"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Μεταβείτε στις Ρυθμίσεις για να ενημερώσετε την πλοήγηση συστήματος"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Κατάσταση αναμονής"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Ορίστηκε ως συζήτηση προτεραιότητας"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Συζητήσεις προτεραιότητας"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Αυτές οι συζητ. εμφανίζ. στην κορυφή της λίστας και μπορούν πάντα να προβληθούν όταν η λειτ. προτεραιότ. είναι ενεργή"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Οι φωτογραφίες προφίλ εμφανίζονται στην οθόνη κλειδώματος"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Μπορείτε εύκολα να βρείτε αυτές τις συζητήσεις σε συννεφάκια στην αρχική σας οθόνη"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Διακοπή λειτουργίας Μην ενοχλείτε"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Το κατάλαβα"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ρυθμίσεις"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Μετακινήστε το κουμπί στο άκρο για προσωρινή απόκρυψη"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Μετακίνηση επάνω αριστερά"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Μετακίνηση επάνω δεξιά"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Μετακίνηση κάτω αριστερά"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Μετακίνηση κάτω δεξιά"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Μετακίν. στο άκρο και απόκρυψη"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Μετακ. εκτός άκρου και εμφάν."</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Στοιχεία ελέγχου συσκευής"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Προσθήκη στοιχείων ελέγχου για τις συνδεδεμένες συσκευές σας."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Ρύθμιση στοιχείων ελέγχου συσκευής"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Λιγότερο από <xliff:g id="DURATION">%1$s</xliff:g> πριν"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Περισσότερο από <xliff:g id="DURATION">%1$s</xliff:g> πριν"</string>
<string name="birthday_status" msgid="2596961629465396761">"Γενέθλια"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Είναι τα γενέθλια του χρήστη <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Προσεχώς γενέθλια"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Πλησιάζουν τα γενέθλια του χρήστη <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Επέτειος"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Είναι η επέτειος του χρήστη <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Κοινοποίηση τοποθ."</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> κοινοποιεί την τοποθεσία του"</string>
<string name="new_story_status" msgid="9012195158584846525">"Νέα είδηση"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> κοινοποίησε μια νέα είδηση"</string>
<string name="video_status" msgid="4548544654316843225">"Παρακολούθηση"</string>
<string name="audio_status" msgid="4237055636967709208">"Ακρόαση"</string>
<string name="game_status" msgid="1340694320630973259">"Παίζει τώρα"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Φίλοι"</string>
<string name="empty_status" msgid="5938893404951307749">"Συζήτηση απόψε!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Το περιεχόμενο θα εμφανιστεί σύντομα"</string>
<string name="missed_call" msgid="4228016077700161689">"Αναπάντητη κλήση"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Δείτε πρόσφατα μηνύματα, αναπάντητες κλήσεις και ενημερώσεις κατάστασης"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Συνομιλία"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε ένα μήνυμα"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε μια εικόνα"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Υπάρχει κάποιο πρόβλημα με την ανάγνωση του μετρητή μπαταρίας"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Πατήστε για περισσότερες πληροφορίες."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Δεν ορίστηκε ξυπνητ."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 19d0ca3..ba9ec4c 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -92,8 +92,10 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Top boundary"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Bottom boundary"</string>
+ <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"Top boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -349,8 +351,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blocked"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -422,8 +426,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device\'s microphone."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device’s camera."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
@@ -657,8 +665,8 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Show all"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Unlock to pay"</string>
+ <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
+ <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Unlock to pay"</string>
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Ready"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Set up payment"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 607f6c7..5b38178 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -92,8 +92,10 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Top boundary"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Bottom boundary"</string>
+ <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"Top boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -349,8 +351,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blocked"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -422,8 +426,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device\'s microphone."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device’s camera."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
@@ -657,8 +665,8 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Show all"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Unlock to pay"</string>
+ <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
+ <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Unlock to pay"</string>
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Ready"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Set up payment"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 19d0ca3..ba9ec4c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -92,8 +92,10 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Top boundary"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Bottom boundary"</string>
+ <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"Top boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -349,8 +351,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blocked"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -422,8 +426,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device\'s microphone."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device’s camera."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
@@ -657,8 +665,8 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Show all"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Unlock to pay"</string>
+ <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
+ <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Unlock to pay"</string>
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Ready"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Set up payment"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 19d0ca3..ba9ec4c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -92,8 +92,10 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Top boundary"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Bottom boundary"</string>
+ <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"Top boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
+ <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -349,8 +351,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blocked"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -422,8 +426,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device\'s microphone."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device’s camera."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
@@ -657,8 +665,8 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Show all"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Unlock to pay"</string>
+ <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
+ <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Unlock to pay"</string>
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Ready"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Set up payment"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 03c5eb1..26f2cff 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -92,8 +92,10 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capture more"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Top boundary"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Bottom boundary"</string>
+ <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"Top boundary <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
+ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bottom boundary <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
+ <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Left boundary <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
+ <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Right boundary <xliff:g id="PERCENT">%1$d</xliff:g> percent"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -349,8 +351,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block Camera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute Microphone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Camera access"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mic access"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blocked"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -422,8 +426,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen Record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device microphone."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"To continue, <b><xliff:g id="APP">%s</xliff:g></b> needs access to your device’s camera."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"This unblocks access for all apps and services allowed to use your microphone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"This unblocks access for all apps and services allowed to use your camera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"This unblocks access for all apps and services allowed to use your camera or microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe up to switch apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Drag right to quickly switch apps"</string>
@@ -657,8 +665,8 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Show all"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Unlock to pay"</string>
+ <string name="wallet_app_button_label" msgid="7123784239111190992">"Show all"</string>
+ <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Unlock to pay"</string>
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Ready"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Set up payment"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 3e9f4da..cb11333 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar más"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Descartar captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de la captura de pantalla"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Límite superior"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Límite inferior"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Grabadora de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación constante para una sesión de grabación de pantalla"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de introducción"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicación desactivada"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear cámara"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Silenciar micrófono"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a la cámara"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al micrófono"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Solo emergencia"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabar pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b&gt necesita acceso al micrófono del dispositivo."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b&gt necesita acceso a la cámara del dispositivo."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Quieres desbloquear el micrófono del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Quieres desbloquear la cámara del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Quieres desbloquear la cámara y el micrófono del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Esta acción desbloquea el acceso para todos los servicios y las apps que tengan permitido usar el micrófono."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Esta acción desbloquea el acceso para todos los servicios y las apps que tengan permitido usar la cámara."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Esta acción desbloquea el acceso para todos los servicios y las apps que tengan permitido usar la cámara o el micrófono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Desliza el dedo hacia arriba para cambiar de app"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra a la derecha para cambiar aplicaciones rápidamente"</string>
@@ -527,7 +539,7 @@
<string name="quick_settings_disclosure_named_management_vpns" msgid="4046375645500668555">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> y está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Tu organización puede controlar el tráfico de red en tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"Es posible que <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> controle el tráfico de red en tu perfil de trabajo"</string>
- <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El administrador de IT puede ver la actividad de la red de tu perfil de trabajo"</string>
+ <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El admin. de TI puede ver la actividad de red de tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Es posible que la red esté supervisada"</string>
<string name="quick_settings_disclosure_vpns" msgid="7213546797022280246">"Este dispositivo está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="8117568745060010789">"Tu perfil de trabajo está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Listo"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurar pago"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string>
<string name="add_tile" msgid="6239678623873086686">"Agregar mosaico"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> Descendió de nivel a Silenciada"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Estado:</b> Se clasificó en una posición superior"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Estado:</b> Se clasificó en una posición inferior"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Se muestran siempre en la parte superior de las notificaciones, incluso cuando el Modo prioridad está activado"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversaciones prioritarias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"No se puede configurar aquí este grupo de notificaciones"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Se estableció la conversación como prioritaria"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversaciones prioritarias"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Estas conversaciones aparecen arriba en la lista y están siempre al alcance cuando el Modo prioridad está activado"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Las fotos de perfil se muestran en la pantalla de bloqueo"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Puedes encontrar estas conversaciones con facilidad en burbujas, en las pantalla principal"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Suspender No interrumpir"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botón"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El botón de accesibilidad reemplaza el gesto de accesibilidad\n\n"<annotation id="link">"Ver configuración"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover abajo a la izquierda"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover abajo a la derecha"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover fuera de borde y ocultar"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fuera de borde y mostrar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Agrega controles para los dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles de dispositivos"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Hace menos de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Hace más de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Cumpleaños"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Es el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Cumpleaños pronto"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Pronto será el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Aniversario"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Es el aniversario de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Comparte ubicación"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> está compartiendo su ubicación"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nueva historia"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> compartió una historia nueva"</string>
<string name="video_status" msgid="4548544654316843225">"Mirando"</string>
<string name="audio_status" msgid="4237055636967709208">"Escuchando"</string>
<string name="game_status" msgid="1340694320630973259">"Jugando"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amigos"</string>
<string name="empty_status" msgid="5938893404951307749">"Charlemos esta noche"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"El contenido se mostrará pronto"</string>
<string name="missed_call" msgid="4228016077700161689">"Llamada perdida"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g> o más"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta mensajes recientes, llamadas perdidas y actualizaciones de estado"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversación"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> envió un mensaje"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> envió una imagen"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema al leer el medidor de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Presiona para obtener más información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"No se estableció alarma"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 0eae44b..3fb5ee5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar más"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cerrar captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de captura de pantalla"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Margen superior"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Margen inferior"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Grabación de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicación desactivada"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear cámara"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Silenciar micrófono"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a la cámara"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al micrófono"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Solo llamadas de emergencia"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabar pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b> necesita tener acceso al micrófono del dispositivo."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b> necesita tener acceso a la cámara del dispositivo."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Desbloquear el micrófono del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Desbloquear la cámara del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Desbloquear la cámara y el micrófono del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Si lo haces, todos los servicios y todas las aplicaciones que tengan permiso podrán usar tu micrófono."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Si lo haces, todos los servicios y todas las aplicaciones que tengan permiso podrán usar tu cámara."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Si lo haces, todos los servicios y todas las aplicaciones que tengan permiso podrán usar tu cámara o tu micrófono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Desliza el dedo hacia arriba para cambiar de aplicación"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra hacia la derecha para cambiar rápidamente de aplicación"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Listo"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurar pago"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Se ha producido un problema al obtener tus tarjetas. Inténtalo de nuevo más tarde."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
<string name="add_tile" msgid="6239678623873086686">"Añadir icono"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> cambio a Silencio"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Estado:</b> posición más alta"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Estado:</b> posición más baja"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Mostrar siempre en la parte superior de tus notificaciones, incluso con el modo Prioridad activado"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ajustes"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversaciones prioritarias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"No se pueden usar funciones de conversación con <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Este grupo de notificaciones no se puede configurar aquí"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Ajustes para actualizar la navegación del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Conversación marcada como prioritaria"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversaciones prioritarias"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Estas conversaciones aparecen al principio de tu lista y puedes acceder a ellas con el modo Prioridad activado"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Las imágenes de perfil se muestran en la pantalla de bloqueo"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Puedes encontrar fácilmente estas conversaciones en las burbujas de la pantalla de inicio"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrumpen el modo No molestar"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ajustes"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El botón Accesibilidad ha reemplazado al gesto de accesibilidad\n\nVer configuración"<annotation id="link"></annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover abajo a la izquierda"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover abajo a la derecha"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover al borde y ocultar"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover al borde y mostrar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Añade controles para tus dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar control de dispositivos"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Hace menos de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Hace más de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Fecha de nacimiento"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Hoy es el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Cumpleaños en breve"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Se acerca el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Aniversario"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Es el aniversario de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Compartiendo ubicación"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> está compartiendo su ubicación"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nueva historia"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ha compartido una nueva historia"</string>
<string name="video_status" msgid="4548544654316843225">"Viendo"</string>
<string name="audio_status" msgid="4237055636967709208">"Escuchando"</string>
<string name="game_status" msgid="1340694320630973259">"Reproduciendo"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amigos"</string>
<string name="empty_status" msgid="5938893404951307749">"Charlemos esta noche"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"El contenido se mostrará en breve"</string>
<string name="missed_call" msgid="4228016077700161689">"Llamada perdida"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta los mensajes recientes, las llamadas perdidas y los cambios de estado"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversación"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado un mensaje"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado una imagen"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"No se ha podido leer el indicador de batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca la pantalla para consultar más información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ninguna alarma puesta"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3a92dfa..021093f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Jäädvustage rohkem"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekraanipildist loobumine"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekraanipildi eelvaade"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Ülempiir"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Alampiir"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Sisestusmeetod"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Asukoht"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Asukoht on väljas"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokeeri kaamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Vaigista mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Juurdepääs kaamerale"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Juurdepääs mikrofonile"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Saadaval"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokeeritud"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Meediaseade"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Ainult hädaabikõned"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekraanisalvestus"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Alustage"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Peatage"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Jätkamiseks vajab rakendus <b><xliff:g id="APP">%s</xliff:g></b> juurdepääsu teie seadme mikrofonile."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Jätkamiseks vajab rakendus <b><xliff:g id="APP">%s</xliff:g></b> juurdepääsu teie seadme kaamerale."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kas tühistada seadme mikrofoni blokeerimine?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kas tühistada seadme kaamera blokeerimine?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kas tühistada seadme kaamera ja mikrofoni blokeerimine?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud mikrofoni kasutada."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud kaamerat kasutada."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Sellega tühistatakse juurdepääsu blokeerimine kõikide rakenduste ja teenuste puhul, millel on lubatud kaamerat või mikrofoni kasutada."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Seade"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Rakenduste vahetamiseks pühkige üles"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Lohistage paremale, et rakendusi kiiresti vahetada"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Äratus"</string>
<string name="wallet_title" msgid="5369767670735827105">"Rahakott"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Valmis"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Makseviisi seadistamine"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avage kasutamiseks"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Teie kaartide hankimisel ilmnes probleem, proovige hiljem uuesti"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Tööprofiil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Lennukirežiim"</string>
<string name="add_tile" msgid="6239678623873086686">"Paani lisamine"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Olek:</b> määrati prioriteet Vaikne"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Olek:</b> määrati kõrgem prioriteet"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Olek:</b> määrati madalam prioriteet"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Kuva alati märguannete ülaosas, isegi kui režiim Prioriteetne on sisse lülitatud"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Seaded"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioriteetsed vestlused"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Seda märguannete rühma ei saa siin seadistada"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Süsteemi navigeerimise värskendamiseks avage jaotis Seaded"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Vestlus määrati prioriteetseks"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioriteetsed vestlused"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Need vestlused kuvatakse loendi ülaosas ja jõuavad alati teieni ka siis, kui režiim Prioriteetne on sisse lülitatud"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profiilipildid kuvatakse lukustuskuval"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Leiate need vestlused hõlpsalt avakuval olevatest mullidest"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Funktsioon Mitte segada katkestatakse"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Selge"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Seaded"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaheta"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Juurdepääsetavuse nupp asendas juurdepääsuliigutuse\n\n"<annotation id="link">"Vaadake seadeid"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Teisaldage nupp serva, et see ajutiselt peita"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Teisalda üles vasakule"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Teisalda üles paremale"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Teisalda alla vasakule"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Teisalda alla paremale"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Teisalda serva ja kuva"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Teisalda servast eemale ja kuva"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisage juhtelemendid ühendatud seadmete jaoks"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Seadmete juhtimisvidinate seadistamine"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Vähem kui <xliff:g id="DURATION">%1$s</xliff:g> tagasi"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Üle <xliff:g id="DURATION">%1$s</xliff:g> tagasi"</string>
<string name="birthday_status" msgid="2596961629465396761">"Sünnipäev"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"On kasutaja <xliff:g id="NAME">%1$s</xliff:g> sünnipäev!"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Peagi on sünnipäev"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Varsti on kasutaja <xliff:g id="NAME">%1$s</xliff:g> sünnipäev"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Aastapäev"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"On kasutaja <xliff:g id="NAME">%1$s</xliff:g> tähtpäev"</string>
<string name="location_status" msgid="1294990572202541812">"Asukoha jagamine"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> jagab asukohta"</string>
<string name="new_story_status" msgid="9012195158584846525">"Uus lugu"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> jagas uut lugu"</string>
<string name="video_status" msgid="4548544654316843225">"Vaatamas"</string>
<string name="audio_status" msgid="4237055636967709208">"Kuulamine"</string>
<string name="game_status" msgid="1340694320630973259">"Mängimas"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Sõbrad"</string>
<string name="empty_status" msgid="5938893404951307749">"Vestleme täna õhtul!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Sisu kuvatakse peagi"</string>
<string name="missed_call" msgid="4228016077700161689">"Vastamata kõne"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Vaadake hiljutisi sõnumeid, vastamata kõnesid ja olekuvärskendusi"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Vestlus"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> saatis sõnumi"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> saatis pildi"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem akumõõdiku lugemisel"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Puudutage lisateabe saamiseks"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Äratust pole"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 1d69d31..7adba36 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Atera eduki gehiago argazkian"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Baztertu pantaila-argazkia"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pantaila-argazkiaren aurrebista"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Goiko ertza"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Beheko ertza"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Pantaila-grabagailua"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Idazketa-metodoa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Kokapena"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Kokapena desaktibatuta"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokeatu kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Desaktibatu mikrofonoa"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera atzitzeko baimena"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonoa atzitzeko baimena"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Baimenduta"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Baimenik gabe"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Multimedia-gailua"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Larrialdi-deiak soilik"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Pantaila-grabaketa"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hasi"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Gelditu"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Aurrera egiteko, gailuaren mikrofonoa atzitzeko baimena behar du <b><xliff:g id="APP">%s</xliff:g></b> aplikazioak."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Aurrera egiteko, gailuaren kamera atzitzeko baimena behar du <b><xliff:g id="APP">%s</xliff:g></b> aplikazioak."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Gailuaren mikrofonoa desblokeatu nahi duzu?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Gailuaren kamera desblokeatu nahi duzu?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Gailuaren kamera eta mikrofonoa desblokeatu nahi dituzu?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Mikrofonoa atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamera atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera edo mikrofonoa atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dituzte."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Gailua"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Egin gora aplikazioa aldatzeko"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastatu eskuinera aplikazioa azkar aldatzeko"</string>
@@ -455,7 +467,7 @@
<string name="camera_hint" msgid="4519495795000658637">"Pasatu hatza ikonotik, kamera irekitzeko"</string>
<string name="interruption_level_none_with_warning" msgid="8394434073508145437">"Isiltasun osoa. Pantaila-irakurgailuak ere isilaraziko dira."</string>
<string name="interruption_level_none" msgid="219484038314193379">"Isiltasun osoa"</string>
- <string name="interruption_level_priority" msgid="661294280016622209">"Lehentasunezkoak"</string>
+ <string name="interruption_level_priority" msgid="661294280016622209">"Lehentasunezkoak soilik"</string>
<string name="interruption_level_alarms" msgid="2457850481335846959">"Alarmak soilik"</string>
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"Isiltasun\nosoa"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Lehentasunezkoak\nsoilik"</string>
@@ -496,8 +508,8 @@
<string name="battery_saver_notification_title" msgid="8419266546034372562">"Aktibatuta dago bateria-aurrezlea"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Errendimendua eta atzeko planoko datuak murrizten ditu"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desaktibatu bateria-aurrezlea"</string>
- <string name="media_projection_dialog_text" msgid="1755705274910034772">"Zerbait grabatzen edo igortzen duzunean, pantailan ikus daitekeen edo gailuak erreproduzitzen duen informazio guztia atzitu ahalko du <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Horrek barne hartzen ditu pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak."</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Zerbait grabatzen edo igortzen duzunean, pantailan ikus daitekeen edo gailuak erreproduzitzen duen informazio guztia atzitu ahalko du funtzio hori eskaintzen duen zerbitzuak. Horrek barne hartzen ditu pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak."</string>
+ <string name="media_projection_dialog_text" msgid="1755705274910034772">"Zerbait grabatzen edo igortzen duzunean, pantailan ikus daitekeen edo gailuak erreproduzitzen duen informazio guztia atzitu ahalko du <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak; besteak beste, pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak."</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Zerbait grabatzen edo igortzen duzunean, pantailan ikus daitekeen edo gailuak erreproduzitzen duen informazio guztia atzitu ahalko du funtzio hori eskaintzen duen zerbitzuak; besteak beste, pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Grabatzen edo igortzen hasi nahi duzu?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioarekin grabatzen edo igortzen hasi nahi duzu?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"Ez erakutsi berriro"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Prest"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Konfiguratu ordainketa"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desblokeatu erabiltzeko"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Arazo bat izan da txartelak eskuratzean. Saiatu berriro geroago."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Work profila"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string>
<string name="add_tile" msgid="6239678623873086686">"Gehitu lauza"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"Soinurik gabeko modura aldatu da <b>egoera:</b>"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"Mailaz igo da <b>egoera:</b>"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"Mailaz jaitsi da <b>egoera:</b>"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Jakinarazpenen goialdean agertuko dira beti, baita lehentasunezko modua aktibatuta dagoenean ere"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ezarpenak"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Lehentasunezko elkarrizketak"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Jakinarazpen talde hau ezin da konfiguratu hemen"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemaren nabigazioa eguneratzeko, joan Ezarpenak atalera"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Lehentasunezko gisa ezarritako elkarrizketa"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Lehentasunezko elkarrizketak"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Elkarrizketak zerrendaren goialdean agertuko dira. Lehentasunezko modua aktibatuta badago, beti iritsiko zaizkie mezuak."</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profileko argazkiak pantaila blokeatuan agertzen dira"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Erraz aurki ditzakezu elkarrizketa horiek hasierako pantailako burbuiletan"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Eten ez molestatzeko modua"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ados"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ezarpenak"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botoia"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Erabilerraztasuna botoiak erabilerraztasun-keinua ordezkatu du\n\n"<annotation id="link">"Ikusi ezarpenak"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Eraman botoia ertzera aldi baterako ezkutatzeko"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Eraman goialdera, ezkerretara"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Eraman goialdera, eskuinetara"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Eraman behealdera, ezkerretara"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Eraman behealdera, eskuinetara"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Eraman ertzera eta ezkutatu"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Atera ertzetik eta erakutsi"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Gailuak kontrolatzeko widgetak"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Gehitu konektatutako gailuak kontrolatzeko widgetak"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguratu gailuak kontrolatzeko widgetak"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Duela <xliff:g id="DURATION">%1$s</xliff:g> baino gutxiago"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Duela <xliff:g id="DURATION">%1$s</xliff:g> baino gehiago"</string>
<string name="birthday_status" msgid="2596961629465396761">"Urtebetetzea"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen urtebetetzea da"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Badator urtebetetzea"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Badator <xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen urtebetetzea"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Urteurrena"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen urteurrena da"</string>
<string name="location_status" msgid="1294990572202541812">"Kokapena partekatzen"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> kokapena partekatzen ari da"</string>
<string name="new_story_status" msgid="9012195158584846525">"Istorio berria"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak istorio berri bat partekatu du"</string>
<string name="video_status" msgid="4548544654316843225">"Ikusten"</string>
<string name="audio_status" msgid="4237055636967709208">"Entzuten"</string>
<string name="game_status" msgid="1340694320630973259">"Erreproduzitzen"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Lagunak"</string>
<string name="empty_status" msgid="5938893404951307749">"Txatea dezagun gaur gauean!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Laster agertuko da edukia"</string>
<string name="missed_call" msgid="4228016077700161689">"Dei galdua"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Ikusi azken mezuak, dei galduak eta egoerari buruzko informazio eguneratua"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Elkarrizketa"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak mezu bat bidali du"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak irudi bat bidali du"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Arazo bat gertatu da bateria-neurgailua irakurtzean"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Informazio gehiago lortzeko, sakatu hau"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ez da ezarri alarmarik"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 543d83b..11bb41b 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -66,7 +66,7 @@
<string name="wifi_debugging_title" msgid="7300007687492186076">"اشکالزدایی بیسیم در این شبکه مجاز شود؟"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"نام شبکه (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nنشانی Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"همیشه در این شبکه مجاز شود"</string>
- <string name="wifi_debugging_allow" msgid="4573224609684957886">"مجاز"</string>
+ <string name="wifi_debugging_allow" msgid="4573224609684957886">"مجاز بودن"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"اشکالزدایی بیسیم مجاز نیست"</string>
<string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"کاربری که درحالحاضر در این دستگاه به سیستم وارد شده است نمیتواند اشکالزدایی بیسیم را روشن کند. برای استفاده از این ویژگی، به کاربر اصلی بروید."</string>
<string name="usb_contaminant_title" msgid="894052515034594113">"درگاه USB غیرفعال شده است"</string>
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ضبط محتوای بیشتر"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"رد کردن نماگرفت"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"پیشنمایش نماگرفت"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"مرز بالایی"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"مرز پایینی"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ضبطکننده صفحهنمایش"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحهنمایش"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحهنمایش"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"روش ورودی"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مکان"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"مکان خاموش"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"مسدود کردن دوربین"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"بیصدا کردن میکروفون"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"دسترسی به دوربین"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"دسترسی به میکروفون"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"دردسترس"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"مسدود"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"دستگاه رسانه"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"فقط تماسهای اضطراری"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ضبط کردن صفحهنمایش"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"توقف"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"برای ادامه دادن، <b><xliff:g id="APP">%s</xliff:g></b> باید به میکروفون دستگاه دسترسی داشته باشد."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"برای ادامه دادن، <b><xliff:g id="APP">%s</xliff:g></b> باید به دوربین دستگاه دسترسی داشته باشد."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"دوربین و میکروفون دستگاه لغو انسداد شود؟"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"با این کار دسترسی برای همه برنامهها و سرویسهایی که مجاز هستند از میکروفونتان استفاده کنند لغو انسداد میشود."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"با این کار دسترسی برای همه برنامهها و سرویسهایی که مجاز هستند از دوربینتان استفاده کنند لغو انسداد میشود."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"با این کار دسترسی برای همه برنامهها و دستگاههایی که مجاز هستند از دوربین یا میکروفونتان استفاده کنند لغو انسداد میشود."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"دستگاه"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"برای تغییر برنامهها، تند بهبالا بکشید"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"برای جابهجایی سریع میان برنامهها، به چپ بکشید"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"اترنت"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"زنگ"</string>
<string name="wallet_title" msgid="5369767670735827105">"کیفپول"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"نمایش همه"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"برای پرداخت قفل را باز کنید"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"آماده"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"راهاندازی پرداخت"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"برای استفاده، قفل را باز کنید"</string>
@@ -758,7 +772,7 @@
<string name="feedback_ok" msgid="6481426753298857144">"تأیید"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"کنترلهای اعلان برای <xliff:g id="APP_NAME">%1$s</xliff:g> باز شد"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"کنترلهای اعلان برای <xliff:g id="APP_NAME">%1$s</xliff:g> بسته شد"</string>
- <string name="notification_channel_switch_accessibility" msgid="8979885820432540252">"مجاز کردن اعلانهای این کانال"</string>
+ <string name="notification_channel_switch_accessibility" msgid="8979885820432540252">"مجاز بودن اعلانهای این کانال"</string>
<string name="notification_more_settings" msgid="4936228656989201793">"تنظیمات بیشتر"</string>
<string name="notification_app_settings" msgid="8963648463858039377">"سفارشی کردن"</string>
<string name="notification_done" msgid="6215117625922713976">"تمام"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index c8de17b..96e083a 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Kuvaa enemmän"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Hylkää kuvakaappaus"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Kuvakaappauksen esikatselu"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Yläraja"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Alaraja"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Näytön tallentaja"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Syöttötapa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sijainti"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Sijainti ei käytössä"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Estä kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mykistä mikrofoni"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Pääsy kameraan"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Pääsy mikrofoniin"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Käytettävissä"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Estetty"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medialaite"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Vain hätäpuhelut"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Tallennus"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Aloita"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Lopeta"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Jotta voit jatkaa, <b><xliff:g id="APP">%s</xliff:g></b> tarvitsee pääsyn laitteesi mikrofoniin."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Jotta voit jatkaa, <b><xliff:g id="APP">%s</xliff:g></b> tarvitsee pääsyn laitteesi kameraan."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kumotaanko laitteen mikrofonin esto?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kumotaanko laitteen kameran esto?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kumotaanko laitteen kameran ja mikrofonin esto?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tämä kumoaa kaikkien sellaisten sovellusten ja palveluiden eston, joilla on lupa käyttää mikrofoniasi."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tämä kumoaa kaikkien sellaisten sovellusten ja palveluiden eston, joilla on lupa käyttää kameraasi."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tämä kumoaa kaikkien sellaisten sovellusten ja palveluiden eston, joilla on lupa käyttää kameraasi tai mikrofoniasi."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Laite"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Vaihda sovellusta pyyhkäisemällä ylös"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Vaihda sovellusta nopeasti vetämällä oikealle"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Herätys"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Valmis"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Ota maksutapa käyttöön"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avaa lukitus ja käytä"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Korttien noutamisessa oli ongelma, yritä myöhemmin uudelleen"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Työprofiili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Lentokonetila"</string>
<string name="add_tile" msgid="6239678623873086686">"Lisää ruutu"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Tila:</b> hiljennetty"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Tila:</b> valittu tärkeämmäksi"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Tila:</b> valittu vähemmän tärkeäksi"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Näytetään aina ilmoitusten yläpuolella, myös silloin, kun Tärkeät-tila on päällä"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Asetukset"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Tärkeät keskustelut"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Tätä ilmoitusryhmää ei voi määrittää tässä"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Vaihda järjestelmän navigointitapaa asetuksista"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Tärkeäksi merkitty keskustelu"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Tärkeät keskustelut"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Nämä keskustelut näkyvät luettelon yläosassa ja ne näkyvät sinulle aina, kun Tärkeät-tila on päällä"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profiilikuvat näkyvät lukitusnäytöllä"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Voit löytää nämä keskustelut helposti aloitusnäytöllä olevista kuplista"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Keskeyttää Älä häiritse ‑tilan"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Selvä"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Asetukset"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaihda"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Esteettömyyspainike on korvannut esteettömyyseleen\n\n"<annotation id="link">"Katso asetukset"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Piilota painike tilapäisesti siirtämällä se reunaan"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Siirrä vasempaan yläreunaan"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Siirrä oikeaan yläreunaan"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Siirrä vasempaan alareunaan"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Siirrä oikeaan alareunaan"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Siirrä reunaan ja piilota"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Siirrä pois reunasta ja näytä"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Laitteiden hallinta"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisää ohjaimia yhdistettyjä laitteita varten"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Laitteiden hallinnan käyttöönotto"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Alle <xliff:g id="DURATION">%1$s</xliff:g> sitten"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Yli <xliff:g id="DURATION">%1$s</xliff:g> sitten"</string>
<string name="birthday_status" msgid="2596961629465396761">"Syntymäpäivä"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> viettää tänään syntymäpäiväänsä"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Syntymäpäivä pian"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> viettää pian syntymäpäiväänsä"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Vuosipäivä"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> juhlii tänään vuosipäiväänsä"</string>
<string name="location_status" msgid="1294990572202541812">"Sijaintia jaetaan"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> jakaa sijaintia"</string>
<string name="new_story_status" msgid="9012195158584846525">"Uusi juttu"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> jakoi uuden tarinan"</string>
<string name="video_status" msgid="4548544654316843225">"Katsotaan"</string>
<string name="audio_status" msgid="4237055636967709208">"Kuunnellaan"</string>
<string name="game_status" msgid="1340694320630973259">"Toistetaan"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Kaverit"</string>
<string name="empty_status" msgid="5938893404951307749">"Jutellaan illalla!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Sisältö tulee pian näkyviin"</string>
<string name="missed_call" msgid="4228016077700161689">"Vastaamaton puhelu"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Yli <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Katso viimeaikaiset viestit, vastaamattomat puhelut ja tilapäivitykset"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Keskustelu"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> lähetti viestin"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> lähetti kuvan"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ongelma akkumittarin lukemisessa"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Saat lisätietoja napauttamalla"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ei herätyksiä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index df9b7b8..abbf161 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturer plus"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Limite supérieure"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Limite inférieure"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Mode de saisie"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Position"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localisation désactivée"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquer l\'appareil photo"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Désactiver le microphone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accès à l\'appareil photo"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Accès au microphone"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Accessible"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqué"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Appareil multimédia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Appels d\'urgence uniquement"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Enregistrement d\'écran"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Pour continuer, vous devez accorder l\'accès au microphone de votre appareil à l\'application <b><xliff:g id="APP">%s</xliff:g></b>."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Pour continuer, vous devez accorder l\'accès à l\'appareil photo de votre appareil à l\'application <b><xliff:g id="APP">%s</xliff:g></b>."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le microphone de l\'appareil?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer l\'appareil photo de l\'appareil?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le microphone?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Cette action débloque l\'accès à toutes les applications et à tous les services qui possèdent l\'autorisation d\'utiliser le microphone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Cette action débloque l\'accès à toutes les applications et à tous les services qui possèdent l\'autorisation d\'utiliser l\'appareil photo."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Cette action débloque l\'accès à toutes les applications et à tous les services qui possèdent l\'autorisation d\'utiliser l\'appareil photo ou le microphone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Balayez vers le haut pour changer d\'application"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Balayez l\'écran vers la droite pour changer rapidement d\'application"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Prêt"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurer le paiement"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Un problème est survenu lors de la récupération de vos cartes, veuillez réessayer plus tard"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
<string name="add_tile" msgid="6239678623873086686">"Ajouter la tuile"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>État :</b> abaissé à la catégorie Silencieux"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>État :</b> élevé d\'un niveau"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>État :</b> abaissé d\'un niveau"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"S\'affiche toujours en haut de vos notifications, même en mode Prioritaire"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversations prioritaires"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les fonctionnalités de conversation"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ce groupe de notifications ne peut pas être configuré ici"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez au menu Paramètres pour mettre à jour la navigation système"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"La conversation a été définie comme prioritaire"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversations prioritaires"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ces conversations s\'affichent dans le haut de votre liste et restent visibles en mode Prioritaire"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Les photos de profil sont affichées sur l\'écran de verrouillage"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Vous trouverez facilement ces conversations dans des bulles sur votre écran d\'accueil"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompre le mode Ne pas déranger"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Commutateur"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Le bouton d\'accessibilité a remplacé le geste d\'accessibilité\n\n"<annotation id="link">"Voir les paramètres"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacez le bouton vers le bord pour le masquer temporairement"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer dans coin sup. gauche"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer dans coin sup. droit"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Déplacer dans coin inf. gauche"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer dans coin inf. droit"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Éloigner du bord et masquer"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajoutez des commandes pour vos appareils connectés"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Il y a moins de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Il y a plus de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Anniversaire"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"C\'est l\'anniversaire de naissance de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Anniversaire proche"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Ce sera bientôt l\'anniversaire de naissance de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Anniversaire"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"C\'est l\'anniversaire de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Partage de position"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> partage sa position"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nouvel article"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> a partagé une nouvelle histoire"</string>
<string name="video_status" msgid="4548544654316843225">"En train de regarder…"</string>
<string name="audio_status" msgid="4237055636967709208">"En train d\'écouter…"</string>
<string name="game_status" msgid="1340694320630973259">"En train de jouer…"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amis"</string>
<string name="empty_status" msgid="5938893404951307749">"Clavardons ce soir!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Le contenu sera bientôt affiché"</string>
<string name="missed_call" msgid="4228016077700161689">"Appel manqué"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Afficher les messages récents, les appels manqués et les mises à jour d\'état"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu lors de la lecture du niveau de charge de la pile"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Touchez pour en savoir plus"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Aucune alarme définie"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 6efdbd0..31d4854 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturer plus"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Limite supérieure"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Limite inférieure"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Mode de saisie"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localisation désactivée"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquer l\'appareil photo"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Couper le micro"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Appareil multimédia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Appels d\'urgence"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Enregistrement de l\'écran"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Pour continuer, <b><xliff:g id="APP">%s</xliff:g></b> a besoin d\'accéder au micro de votre appareil."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Pour continuer, <b><xliff:g id="APP">%s</xliff:g></b> a besoin d\'accéder à l\'appareil photo de votre appareil."</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"Appareil"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Balayer l\'écran vers le haut pour changer d\'application"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Déplacer vers la droite pour changer rapidement d\'application"</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Prêt"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurer un mode de paiement"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Problème de récupération de vos cartes. Réessayez plus tard"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
<string name="add_tile" msgid="6239678623873086686">"Ajouter un bloc"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>État :</b> Abaissée à la catégorie \"Silencieux\""</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>État :</b> Élevée d\'un niveau"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>État ::</b> Abaissée d\'un niveau"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"S\'affiche toujours en haut des notifications, même en mode Prioritaire"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversations prioritaires"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les fonctionnalités de conversation"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Vous ne pouvez pas configurer ce groupe de notifications ici"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez aux paramètres pour mettre à jour la navigation système"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Conversation définie comme prioritaire"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversations prioritaires"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ces conversations s\'affichent en haut de la liste et restent visibles en mode Prioritaire"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Les photos de profil s\'affichent sur l\'écran de verrouillage"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Retrouvez facilement ces conversations dans des bulles sur l\'écran d\'accueil"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompre Ne pas déranger"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</string>
@@ -1040,18 +1052,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Changer"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Le bouton Accessibilité a remplacé le geste d\'accessibilité\n\n"<annotation id="link">"Afficher les paramètres"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacer le bouton vers le bord pour le masquer temporairement"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer en haut à gauche"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer en haut à droite"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Déplacer en bas à gauche"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer en bas à droite"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Rapprocher du bord et masquer"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajouter des commandes pour vos appareils connectés"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Il y a moins de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Il y a plus de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Anniversaire"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"C\'est l\'anniversaire de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Anniversaire à venir"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"C\'est bientôt l\'anniversaire de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Fête"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"C\'est l\'anniversaire de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Partage sa position"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> partage sa position"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nouvelle story"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> a partagé une story"</string>
<string name="video_status" msgid="4548544654316843225">"Regarde une vidéo"</string>
<string name="audio_status" msgid="4237055636967709208">"Écoute"</string>
<string name="game_status" msgid="1340694320630973259">"Joue"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amis"</string>
<string name="empty_status" msgid="5938893404951307749">"Chattez ce soir !"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Le contenu s\'affichera bientôt"</string>
<string name="missed_call" msgid="4228016077700161689">"Appel manqué"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ de <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Voir les messages récents, les appels manqués et les notifications d\'état"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu au niveau de la lecture de votre outil de mesure de batterie"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Appuyer pour en savoir plus"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Pas d\'alarme définie"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index eeacc9f..9c584bb 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar máis"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar a captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa da captura de pantalla"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Bordo superior"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Bordo inferior"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Gravadora da pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación en curso sobre unha sesión de gravación de pantalla"</string>
@@ -332,7 +338,7 @@
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="6375098046500790870">"Bluetooth desactivado"</string>
- <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Non hai dispositivos sincronizados dispoñibles"</string>
+ <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Non hai dispositivos vinculados dispoñibles"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de introdución de texto"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localización"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localización desactivada"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear cámara"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Silenciar micrófono"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso á cámara"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso ao micrófono"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dispoñible"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Só chamadas de emerxencia"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravación da pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Deter"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b> precisa acceder ao micrófono do dispositivo."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b> precisa acceder á cámara do dispositivo."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Queres desbloquear o micrófono do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Queres desbloquear a cámara do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Queres desbloquear a cámara e o micrófono do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Con esta acción desbloquearase o acceso ao micrófono para todas as aplicacións e servizos que teñan permiso para utilizalo."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Con esta acción desbloquearase o acceso á cámara para todas as aplicacións e servizos que teñan permiso para utilizala."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Con esta acción desbloquearase o acceso á cámara ou ao micrófono para todas as aplicacións e servizos que teñan permiso para utilizalos."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Pasar o dedo cara arriba para cambiar de aplicación"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arrastra cara á dereita para cambiar de aplicacións rapidamente"</string>
@@ -447,9 +459,9 @@
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasa o dedo cara arriba para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Pasa o dedo cara arriba para tentalo de novo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
- <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización"</string>
- <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> proporciona este dispositivo"</string>
+ <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización."</string>
+ <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> proporciona este dispositivo."</string>
<string name="phone_hint" msgid="6682125338461375925">"Pasa o dedo desde a icona para acceder ao teléfono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Pasa o dedo desde a icona para acceder ao asistente de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Pasa o dedo desde a icona para acceder á cámara"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Listo"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurar pago"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Produciuse un problema ao obter as tarxetas. Téntao de novo máis tarde"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de traballo"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
<string name="add_tile" msgid="6239678623873086686">"Engade un atallo"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> o nivel diminuíuse a Silencioso"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Estado:</b> clasificouse nun nivel superior"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Estado:</b> clasificouse nun nivel inferior"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Móstrase sempre na parte superior das notificacións, mesmo cando está activado o modo de prioridade"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversas prioritarias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquí non se pode configurar este grupo de notificacións"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Para actualizar a navegación do sistema, vai a Configuración"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"A conversa definiuse como prioritaria"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversas prioritarias"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Estas conversas móstranse na parte superior da lista e pódenseche amosar mesmo co modo de prioridade activado"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"As fotos dos perfís móstranse na pantalla de bloqueo"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Podes atopar facilmente estas conversas en burbullas situadas na pantalla de inicio"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interromper modo Non molestar"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botón de accesibilidade substituíu o xesto de accesibilidade\n\n"<annotation id="link">"Ver configuración"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Para ocultar temporalmente o botón, móveo ata o bordo"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover á parte super. esquerda"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover á parte superior dereita"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover á parte infer. esquerda"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover á parte inferior dereita"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover ao bordo e ocultar"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fóra do bordo e mostrar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Engade controis para os dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar o control de dispositivos"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Hai menos de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Hai máis de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversario"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> está de aniversario"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversario a caer"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> estará de aniversario pronto"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Aniversario"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> está de aniversario"</string>
<string name="location_status" msgid="1294990572202541812">"Compartindo localiz."</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> está compartindo a localización"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nova historia"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> compartiu unha historia nova"</string>
<string name="video_status" msgid="4548544654316843225">"Vendo vídeo"</string>
<string name="audio_status" msgid="4237055636967709208">"Escoitando"</string>
<string name="game_status" msgid="1340694320630973259">"Xogando"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amigos"</string>
<string name="empty_status" msgid="5938893404951307749">"Chateamos á noite?"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"O contido aparecerá pronto"</string>
<string name="missed_call" msgid="4228016077700161689">"Chamada perdida"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ de <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta as mensaxes recentes, as chamadas perdidas e as actualizacións dos estados"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha mensaxe"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha imaxe"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Produciuse un problema ao ler o medidor da batería"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca para obter máis información"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Sen alarmas postas"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 57bbb08..37ff5e7 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"વધુ કૅપ્ચર કરો"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"સ્ક્રીનશૉટ છોડી દો"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"સ્ક્રીનશૉટની સૌથી ઉપરની બાજુની સીમા"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"સ્ક્રીનશૉટની સૌથી નીચેની બાજુની સીમા"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકૉર્ડર"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
@@ -201,7 +207,7 @@
<string name="accessibility_wimax_three_bars" msgid="2773714362377629938">"WiMAX ત્રણ બાર."</string>
<string name="accessibility_wimax_signal_full" msgid="3101861561730624315">"પૂર્ણ WiMAX સિગ્નલ."</string>
<string name="accessibility_no_signal" msgid="1115622734914921920">"કોઈ સિગ્નલ નથી."</string>
- <string name="accessibility_not_connected" msgid="4061305616351042142">"કનેક્ટ થયેલ નથી."</string>
+ <string name="accessibility_not_connected" msgid="4061305616351042142">"કનેક્ટ થયેલું નથી."</string>
<string name="accessibility_zero_bars" msgid="1364823964848784827">"શૂન્ય બાર."</string>
<string name="accessibility_one_bar" msgid="6312250030039240665">"એક બાર."</string>
<string name="accessibility_two_bars" msgid="1335676987274417121">"બે બાર."</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ઇનપુટ પદ્ધતિ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"સ્થાન"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"સ્થાન બંધ"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"કૅમેરા બ્લૉક કરો"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"માઇક્રોફોનને મ્યૂટ કરો"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"મીડિયા ઉપકરણ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ફક્ત ઇમર્જન્સી કૉલ"</string>
@@ -363,7 +375,7 @@
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ઇન્ટરનેટ"</string>
<string name="quick_settings_networks_available" msgid="1875138606855420438">"નેટવર્ક ઉપલબ્ધ છે"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"નેટવર્ક અનુપલબ્ધ છે"</string>
- <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"કનેક્ટ થયેલ નથી"</string>
+ <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"કનેક્ટ થયેલું નથી"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"કોઈ નેટવર્ક નથી"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"વાઇ-ફાઇ બંધ"</string>
<string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"વાઇ-ફાઇ ચાલુ"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"સ્ક્રીન રેકૉર્ડ કરો"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"શરૂ કરો"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"રોકો"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ચાલુ રાખવા માટે, <b><xliff:g id="APP">%s</xliff:g></b>ને તમારા ડિવાઇસના માઇક્રોફોનના ઍક્સેસની જરૂર છે."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ચાલુ રાખવા માટે, <b><xliff:g id="APP">%s</xliff:g></b>ને તમારા ડિવાઇસના કૅમેરાના ઍક્સેસની જરૂર છે."</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"ડિવાઇસ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ઍપ સ્વિચ કરવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ઍપને ઝડપથી સ્વિચ કરવા માટે જમણે ખેંચો"</string>
@@ -510,7 +532,7 @@
<string name="notification_section_header_conversations" msgid="821834744538345661">"વાતચીત"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"બધા સાઇલન્ટ નોટિફિકેશન સાફ કરો"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ખલેલ પાડશો નહીં દ્વારા થોભાવેલ નોટિફિકેશન"</string>
- <string name="media_projection_action_text" msgid="3634906766918186440">"હવે પ્રારંભ કરો"</string>
+ <string name="media_projection_action_text" msgid="3634906766918186440">"હવે શરૂ કરો"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"કોઈ નોટિફિકેશન નથી"</string>
<string name="profile_owned_footer" msgid="2756770645766113964">"પ્રોફાઇલ મૉનિટર કરી શકાય છે"</string>
<string name="vpn_footer" msgid="3457155078010607471">"નેટવર્ક મૉનિટર કરી શકાય છે"</string>
@@ -534,7 +556,7 @@
<string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="5481763430080807797">"તમારી વ્યક્તિગત પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g>થી કનેક્ટ કરેલી છે"</string>
<string name="quick_settings_disclosure_named_vpn" msgid="2350838218824492465">"આ ડિવાઇસ <xliff:g id="VPN_APP">%1$s</xliff:g>થી કનેક્ટ કરેલું છે"</string>
<string name="monitoring_title_financed_device" msgid="3659962357973919387">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> દ્વારા પ્રદાન કરવામાં આવેલું છે"</string>
- <string name="monitoring_title_device_owned" msgid="7029691083837606324">"ઉપકરણનું સંચાલન"</string>
+ <string name="monitoring_title_device_owned" msgid="7029691083837606324">"ડિવાઇસ મેનેજમેન્ટ"</string>
<string name="monitoring_title_profile_owned" msgid="6301118649405449568">"પ્રોફાઇલ નિરીક્ષણ"</string>
<string name="monitoring_title" msgid="4063890083735924568">"નેટવર્ક મૉનિટરિંગ"</string>
<string name="monitoring_subtitle_vpn" msgid="800485258004629079">"VPN"</string>
@@ -551,7 +573,7 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"તમારી સંસ્થાએ તમારી કાર્ય પ્રોફાઇલમાં પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કર્યું છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"આ ઉપકરણ પર પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કરેલ છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યું છે, જે તમારા ઉપકરણ પર નેટવર્ક ટ્રાફિકનું નિયમન કરે છે."</string>
- <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગ ઇન ચાલુ કર્યુ છે, જે તમારી વ્યક્તિગત પ્રોફાઇલમાં નહીં, પરંતુ ઑફિસની પ્રોફાઇલમાં ટ્રાફિકનું નિરીક્ષણ કરે છે."</string>
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગ ઇન ચાલુ કર્યું છે, જે તમારી વ્યક્તિગત પ્રોફાઇલમાં નહીં, પરંતુ ઑફિસની પ્રોફાઇલમાં ટ્રાફિકનું નિરીક્ષણ કરે છે."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"તમે <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"તમે <xliff:g id="VPN_APP_0">%1$s</xliff:g> અને <xliff:g id="VPN_APP_1">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
@@ -616,7 +638,7 @@
<string name="stream_system" msgid="7663148785370565134">"સિસ્ટમ"</string>
<string name="stream_ring" msgid="7550670036738697526">"રિંગ વગાડો"</string>
<string name="stream_music" msgid="2188224742361847580">"મીડિયા"</string>
- <string name="stream_alarm" msgid="16058075093011694">"એલાર્મ"</string>
+ <string name="stream_alarm" msgid="16058075093011694">"અલાર્મ"</string>
<string name="stream_notification" msgid="7930294049046243939">"નોટિફિકેશન"</string>
<string name="stream_bluetooth_sco" msgid="6234562365528664331">"બ્લૂટૂથ"</string>
<string name="stream_dtmf" msgid="7322536356554673067">"દ્વિ બહુ ટોન આવર્તન"</string>
@@ -655,20 +677,16 @@
<string name="enable_demo_mode" msgid="3180345364745966431">"ડેમો મોડ સક્ષમ કરો"</string>
<string name="show_demo_mode" msgid="3677956462273059726">"ડેમો મોડ બતાવો"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"ઇથરનેટ"</string>
- <string name="status_bar_alarm" msgid="87160847643623352">"એલાર્મ"</string>
+ <string name="status_bar_alarm" msgid="87160847643623352">"અલાર્મ"</string>
<string name="wallet_title" msgid="5369767670735827105">"વૉલેટ"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"તૈયાર છે"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ચુકવણી પદ્ધતિનું સેટઅપ કરો"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string>
<string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string>
<string name="add_tile" msgid="6239678623873086686">"ટાઇલ ઉમેરો"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>સ્ટેટસ:</b> સાઇલન્ટ પર અવનત કરવામાં આવ્યું"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>સ્ટેટસ:</b> ઉપલી રેંક આપવામાં આવી"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>સ્ટેટસ:</b> નીચલી રેંક આપવામાં આવી"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"જ્યારે પ્રાધાન્યતા મોડ ચાલુ હોય ત્યારે પણ તમારા નોટિફિકેશનમાં હંમેશાં સૌથી ઉપર ટોચમાં બતાવવામાં આવશે"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"સેટિંગ"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"પ્રાધાન્યતા ધરાવતી વાતચીતો"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"નોટિફિકેશનના આ ગ્રૂપની ગોઠવણી અહીં કરી શકાશે નહીં"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"વાતચીતને પ્રાધાન્યતા ધરાવતી તરીકે સેટ કરી"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"પ્રાધાન્યતા ધરાવતી વાતચીતો"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"આ વાતચીતોને તમારી સૂચિમાં ટોચ પર બતાવવામાં આવે છે અને જ્યારે પ્રાધાન્યતા મોડ ચાલુ હોય ત્યારે તમને સો ટકા મળશે"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"લૉક સ્ક્રીન પર પ્રોફાઇલ ફોટા બતાવવામાં આવે છે"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"આ વાતચીતોને તમારી હોમ સ્ક્રીન પર તમે સરળતાથી બબલ સ્વરૂપમાં મેળવી શકશો"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ખલેલ પાડશો નહીં સેટિંગમાં હસ્તક્ષેપ કરી શકે છે"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"સમજાઈ ગયું"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"સેટિંગ"</string>
@@ -1040,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"તેને હંગામી રૂપે ખસેડવા માટે બટનને કિનારી પર ખસેડો"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ઉપર ડાબે ખસેડો"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ઉપર જમણે ખસેડો"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"નીચે ડાબે ખસેડો"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"નીચે જમણે ખસેડો"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"કિનારી પર ખસેડો અને છુપાવો"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"કિનારીથી ખસેડો અને બતાવો"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ડિવાઇસનાં નિયંત્રણો"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"તમારા કનેક્ટ કરેલા ડિવાઇસ માટે નિયંત્રણો ઉમેરો"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ડિવાઇસનાં નિયંત્રણો સેટઅપ કરો"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>થી ઓછા સમય પહેલાં"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> કરતાં વધુ સમય પહેલાં"</string>
<string name="birthday_status" msgid="2596961629465396761">"જન્મદિવસ"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"આ તો <xliff:g id="NAME">%1$s</xliff:g>નો જન્મદિવસ છે"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"જલ્દી જ જન્મદિવસ છે"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"ટૂંક સમયમાં <xliff:g id="NAME">%1$s</xliff:g>નો જન્મદિવસ આવશે"</string>
<string name="anniversary_status" msgid="1790034157507590838">"વર્ષગાંઠ"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"આ તો <xliff:g id="NAME">%1$s</xliff:g>ની લગ્નતિથિ છે"</string>
<string name="location_status" msgid="1294990572202541812">"સ્થાન શેર કરીએ છીએ"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> સ્થાન શેર કરી રહ્યાં છે"</string>
<string name="new_story_status" msgid="9012195158584846525">"નવી સ્ટોરી"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા નવી સ્ટોરી શેર કરવામાં આવી"</string>
<string name="video_status" msgid="4548544654316843225">"જોઈ રહ્યાં છે"</string>
<string name="audio_status" msgid="4237055636967709208">"સાંભળી રહ્યાં છીએ"</string>
<string name="game_status" msgid="1340694320630973259">"રમી રહ્યાં છે"</string>
<string name="empty_user_name" msgid="3389155775773578300">"મિત્રો"</string>
<string name="empty_status" msgid="5938893404951307749">"આજે રાતે ચૅટ કરીએ!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"ટૂંક સમયમાં કન્ટેન્ટ બતાવવામાં આવશે"</string>
<string name="missed_call" msgid="4228016077700161689">"ચૂકી ગયેલો કૉલ"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"તાજેતરના મેસેજ, ચૂકી ગયેલા કૉલ અને સ્ટેટસ અપડેટ જુઓ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"વાતચીત"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ સંદેશ મોકલવામાં આવ્યો"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ છબી મોકલવામાં આવી"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"તમારું બૅટરી મીટર વાંચવામાં સમસ્યા આવી"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"કોઈ અલાર્મ સેટ નથી"</string>
diff --git a/packages/SystemUI/res/values-h740dp-port/dimens.xml b/packages/SystemUI/res/values-h740dp-port/dimens.xml
deleted file mode 100644
index 966066f..0000000
--- a/packages/SystemUI/res/values-h740dp-port/dimens.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<resources>
- <dimen name="qs_tile_height">106dp</dimen>
- <dimen name="qs_tile_margin_vertical">24dp</dimen>
-
- <!-- The height of the qs customize header. Should be
- (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) -
- (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
- -->
- <dimen name="qs_customize_header_min_height">46dp</dimen>
- <dimen name="qs_tile_margin_top">18dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index de5741c..ca18fe7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ज़्यादा कॉन्टेंट कैप्चर करें"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट को खारिज करें"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉट की झलक"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"स्क्रीनशॉट को ऊपर से काटने की सीमा"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"स्क्रीनशॉट को नीचे से काटने की सीमा"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"इनपुट विधि"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"जगह"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"जगह की जानकारी बंद है"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"कैमरा ब्लॉक करें"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"माइक्रोफ़ोन म्यूट करें"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"कैमरे का ऐक्सेस"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक्रोफ़ोन का ऐक्सेस"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ब्लॉक किया गया है"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"मीडिया डिवाइस"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"सिर्फ़ आपातकालीन कॉल"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्क्रीन रिकॉर्ड"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"शुरू करें"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोकें"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"जारी रखने के लिए, <b><xliff:g id="APP">%s</xliff:g></b> को आपके डिवाइस का माइक्रोफ़ोन ऐक्सेस करने की ज़रूरत है."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"जारी रखने के लिए, <b><xliff:g id="APP">%s</xliff:g></b> को आपके डिवाइस का कैमरा ऐक्सेस करने की ज़रूरत है."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"क्या आप डिवाइस के माइक्रोफ़ोन को अनब्लॉक करना चाहते हैं?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"क्या आप डिवाइस के कैमरे को अनब्लॉक करना चाहते हैं?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"क्या आप डिवाइस के कैमरे और माइक्रोफ़ोन को अनब्लॉक करना चाहते हैं?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ऐसा करने से, माइक्रोफ़ोन का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें माइक्रोफ़ोन का इस्तेमाल करने की अनुमति दी गई है."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ऐसा करने से, कैमरे का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें कैमरे का इस्तेमाल करने की अनुमति दी गई है."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ऐसा करने से, कैमरे या माइक्रोफ़ोन का ऐक्सेस उन सभी ऐप्लिकेशन और सेवाओं के लिए अनब्लॉक हो जाएगा जिन्हें कैमरे या माइक्रोफ़ोन का इस्तेमाल करने की अनुमति दी गई है."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"डिवाइस"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ऐप्लिकेशन बदलने के लिए ऊपर स्वाइप करें"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ऐप्लिकेशन को झटपट स्विच करने के लिए उसे दाईं ओर खींचें और छोड़ें"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ईथरनेट"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"अलार्म"</string>
<string name="wallet_title" msgid="5369767670735827105">"वॉलेट"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"सभी दिखाएं"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"पेमेंट करने के लिए, डिवाइस अनलॉक करें"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"तैयार है"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"पेमेंट करने का तरीका सेट अप करें"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"इस्तेमाल करने के लिए, डिवाइस अनलॉक करें"</string>
@@ -1008,7 +1022,7 @@
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"बातचीत को \'अहम बातचीत\' के तौर पर सेट किया गया है"</string>
<string name="priority_onboarding_behavior" msgid="636826237468953117">"अहम बातचीत"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ये बातचीत आपकी सूची में सबसे ऊपर दिखती हैं और प्राथमिकता मोड चालू होने पर, हमेशा आप तक पहुंच सकती हैं"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ये बातचीत आपकी सूची में सबसे ऊपर दिखती हैं. साथ ही, अगर आपने प्राथमिकता मोड चालू किया है, तो ये आपको हमेशा दिखेंगी"</string>
<string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"प्रोफ़ाइल फ़ोटो, लॉक स्क्रीन पर दिखती हैं"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"आप इन बातचीत को अपनी होम स्क्रीन पर मौजूद बबल्स में, आसानी से देख सकते हैं"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'परेशान न करें\' मोड में रुकावट"</string>
@@ -1114,7 +1128,7 @@
<string name="birthday_status" msgid="2596961629465396761">"जन्मदिन"</string>
<string name="birthday_status_content_description" msgid="7677415209545817153">"आज <xliff:g id="NAME">%1$s</xliff:g> का जन्मदिन है"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"जन्मदिन आने वाला है"</string>
- <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> का जन्मदिन जल्द आ रहा है"</string>
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> का जन्मदिन आने वाला है"</string>
<string name="anniversary_status" msgid="1790034157507590838">"सालगिरह"</string>
<string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> की सालगिरह है"</string>
<string name="location_status" msgid="1294990572202541812">"जगह की जानकारी शेयर की जा रही है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index cc04dc0..0ed18b5 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Snimite više"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacivanje snimke zaslona"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimke zaslona"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Gornja granica"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Donja granica"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrada snimanja zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Tekuća obavijest za sesiju snimanja zaslona"</string>
@@ -350,8 +356,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Način unosa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokacija je isključena"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokiraj kameru"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Isključi mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Pristup fotoaparatu"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Pristup mikrofonu"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostupno"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokirano"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijski uređaj"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Samo hitni pozivi"</string>
@@ -424,8 +432,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snimač zaslona"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Početak"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavi"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Da bi nastavila s radom, aplikacija <b><xliff:g id="APP">%s</xliff:g></b> treba pristupiti mikrofonu vašeg uređaja."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Da bi nastavila s radom, aplikacija <b><xliff:g id="APP">%s</xliff:g></b> treba pristupiti fotoaparatu vašeg uređaja."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite li deblokirati mikrofon uređaja?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite li deblokirati fotoaparat uređaja?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite li deblokirati fotoaparat i mikrofon uređaja?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg mikrofona."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg fotoaparata."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Time se deblokira pristup za sve aplikacije i usluge kojima je dopuštena upotreba vašeg fotoaparata ili mikrofona."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Uređaj"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Prijeđite prstom prema gore da biste promijenili aplikaciju"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Povucite udesno da biste brzo promijenili aplikaciju"</string>
@@ -660,18 +672,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Novčanik"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Spremno"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Postavi plaćanje"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da biste koristili"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Pojavio se problem prilikom dohvaćanja kartica, pokušajte ponovo kasnije"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u zrakoplovu"</string>
<string name="add_tile" msgid="6239678623873086686">"Dodavanje pločice"</string>
@@ -740,11 +748,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> prebačena u bešumnu"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> više rangirana"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> niže rangirana"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Uvijek se prikazuje pri vrhu obavijesti, čak i kada je uključen način prioritetnih obavijesti"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioritetni razgovori"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ta se grupa obavijesti ne može konfigurirati ovdje"</string>
@@ -1020,14 +1026,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Navigaciju sustavom možete ažurirati u Postavkama"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Razgovor postavljen na prioritetan"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioritetni razgovori"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ti se razgovori prikazuju pri vrhu vašeg popisa i mogu se uvijek prikazati kad je uključen način prioritetnih obavijesti"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profilne slike prikazuju se na zaključanom zaslonu"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Te razgovore možete jednostavno pronaći u oblačićima na početnom zaslonu"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Prekida Ne uznemiravaj"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Shvaćam"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Postavke"</string>
@@ -1045,18 +1047,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prebacivanje"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Gumb za Pristupačnost zamijenio je pokret pristupačnosti\n\n"<annotation id="link">"Prikaz postavki"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomaknite gumb do ruba da biste ga privremeno sakrili"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premjesti u gornji lijevi kut"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premjesti u gornji desni kut"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Premjesti u donji lijevi kut"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premjesti u donji desni kut"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premjesti na rub i sakrij"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ukloni s ruba i prikaži"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodavanje kontrola za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavljanje kontrola uređaja"</string>
@@ -1136,35 +1132,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Prije manje od <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Prije više od <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rođendan"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> ima rođendan"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rođendan uskoro"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Uskoro je rođendan korisnika <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Godišnjica"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Godišnjica je korisnika <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Dijeljenje lokacije"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> dijeli lokaciju"</string>
<string name="new_story_status" msgid="9012195158584846525">"Novi članak"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> podijelio je novu priču"</string>
<string name="video_status" msgid="4548544654316843225">"Gledanje"</string>
<string name="audio_status" msgid="4237055636967709208">"Slušanje"</string>
<string name="game_status" msgid="1340694320630973259">"Igranje"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Prijatelji"</string>
<string name="empty_status" msgid="5938893404951307749">"Može chat večeras?"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Sadržaj će se uskoro prikazati"</string>
<string name="missed_call" msgid="4228016077700161689">"Propušteni poziv"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pogledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Razgovor"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> šalje poruku"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> poslao je sliku"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem s očitavanjem mjerača baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nema nijednog alarma"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 132134a5..86e5308 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Több rögzítése"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Képernyőkép elvetése"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Képernyőkép előnézete"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Felső határ"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Alsó határ"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Képernyőrögzítő"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Folyamatban lévő értesítés képernyőrögzítési munkamenethez"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Beviteli módszer"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Hely kikapcsolva"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Kamera letiltása"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mikrofon némítása"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Hozzáférés a kamerához"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Hozzáférés a mikrofonhoz"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Rendelkezésre áll"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Letiltva"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Médiaeszköz"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Csak segélyhívások"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Képernyő rögzítése"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Indítás"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Leállítás"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"A folytatáshoz a(z) <b><xliff:g id="APP">%s</xliff:g></b> alkalmazásnak hozzáférésre van szüksége az eszköze mikrofonjához."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"A folytatáshoz a(z) <b><xliff:g id="APP">%s</xliff:g></b> alkalmazásnak hozzáférésre van szüksége az eszköze kamerájához."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Feloldja az eszközmikrofon letiltását?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Feloldja az eszközkamera letiltását?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Feloldja az eszközkamera és -mikrofon letiltását?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a mikrofon használatát."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a kamera használatát."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ezzel feloldja a hozzáférés letiltását az összes olyan alkalmazás és szolgáltatás esetében, amelyek számára engedélyezte a kamera vagy a mikrofon használatát."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Eszköz"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Váltás az alkalmazások között felfelé csúsztatással"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Húzza jobbra az ujját az alkalmazások közötti gyors váltáshoz"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Ébresztés"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Kész"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Fizetési mód beállítása"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Oldja fel a használathoz"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Probléma merült fel a kártyák lekérésekor, próbálja újra később"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Munkahelyi profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Repülős üzemmód"</string>
<string name="add_tile" msgid="6239678623873086686">"Mozaik hozzáadása"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Állapot:</b> némára állítva"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Állapot:</b> előrébb sorolva"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Állapot:</b> hátrébb sorolva"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Még akkor is az értesítések tetején jelenik meg, ha a Prioritásos mód be van kapcsolva"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Beállítások"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Fontos beszélgetések"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> nem támogatja a beszélgetési funkciókat"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Az értesítések jelen csoportját itt nem lehet beállítani"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"A rendszer-navigációs lehetőségeket a Beállításokban módosíthatja"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Fontosnak beállított beszélgetés"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Fontos beszélgetések"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ezek a beszélgetések a lista tetején jelennek meg, és mindig megkapja őket, ha a Prioritásos mód be van kapcsolva"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"A profilképek mindig megjelennek a lezárási képernyőn"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Ezeket a beszélgetéseket könnyedén megtalálja a kezdőképernyő tetején lévő buborékokban"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Megszakítják a Ne zavarjanak módot"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Értem"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Beállítások"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Váltás"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"A kisegítő kézmozdulat helyébe a Kisegítő lehetőségek gomb lépett\n\n"<annotation id="link">"Beállítások megtekintése"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"A gombot a szélre áthelyezve ideiglenesen elrejtheti"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Áthelyezés fel és balra"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Áthelyezés fel és jobbra"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Áthelyezés le és balra"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Áthelyezés le és jobbra"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Áthelyezés a szélen kívül és elrejtés"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Áthelyezés a szélen kívül és mutatás"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Vezérlők hozzáadása a csatlakoztatott eszközökhöz"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Eszközvezérlők beállítása"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Kevesebb, mint ennyi ideje: <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Több, mint ennyi ideje: <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Születésnap"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Ma van <xliff:g id="NAME">%1$s</xliff:g> születésnapja"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Közelgő születésnap"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Hamarosan <xliff:g id="NAME">%1$s</xliff:g> születésnapja lesz"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Évforduló"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Ma van <xliff:g id="NAME">%1$s</xliff:g> évfordulója"</string>
<string name="location_status" msgid="1294990572202541812">"Hely megosztása"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> megosztja a tartózkodási helyét"</string>
<string name="new_story_status" msgid="9012195158584846525">"Új történet"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> megosztott egy új történetet"</string>
<string name="video_status" msgid="4548544654316843225">"Lejátszás"</string>
<string name="audio_status" msgid="4237055636967709208">"Figyelés"</string>
<string name="game_status" msgid="1340694320630973259">"Játékban"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Ismerősök"</string>
<string name="empty_status" msgid="5938893404951307749">"Beszélgessünk egyet!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Hamarosan látható lesz a tartalom"</string>
<string name="missed_call" msgid="4228016077700161689">"Nem fogadott hívás"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Megtekintheti a legutóbbi üzeneteket, a nem fogadott hívásokat és az állapotfrissítéseket."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Beszélgetés"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> üzenetet küldött"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> képet küldött"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probléma merült fel az akkumulátor-töltésmérő olvasásakor"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Koppintással további információkat érhet el."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nincs ébresztés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 04a3267..ce158a9 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Մեծացնել սքրինշոթի տարածքը"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Փակել սքրինշոթը"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Սքրինշոթի նախադիտում"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Վերևի սահմանագիծ"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Ներքևի սահմանագիծ"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Էկրանի տեսագրիչ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Մուտքագրման եղանակը"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Տեղորոշում"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Անջատել տեղադրությունը"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Արգելափակել տեսախցիկը"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Անջատել խոսափողը"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Տեսախցիկի հասանելիություն"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Խոսափողի հասանելիություն"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Հասանելի է"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Արգելափակված է"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Մեդիա սարք"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Միայն շտապ կանչեր"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Էկրանի ձայնագրում"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Սկսել"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Կանգնեցնել"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Շարունակելու համար <b><xliff:g id="APP">%s</xliff:g></b> հավելվածին անհրաժեշտ է ձեր սարքի խոսափողի օգտագործման թույլտվություն։"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Շարունակելու համար <b><xliff:g id="APP">%s</xliff:g></b> հավելվածին անհրաժեշտ է ձեր սարքի տեսախցիկի օգտագործման թույլտվություն։"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Արգելահանե՞լ սարքի խոսափողը"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Արգելահանե՞լ սարքի տեսախցիկը"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Արգելահանե՞լ սարքի տեսախցիկը և խոսափողը"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր խոսափողն օգտագործելու թույլտվություն։"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր տեսախցիկն օգտագործելու թույլտվություն։"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Սա բացում է մուտքը բոլոր հավելվածների և ծառայությունների համար, որոնք ունեն ձեր տեսախցիկը կամ խոսափողն օգտագործելու թույլտվություն։"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Սարք"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Սահեցրեք վերև՝ մյուս հավելվածին անցնելու համար"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Քաշեք աջ՝ հավելվածների միջև անցնելու համար"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Զարթուցիչ"</string>
<string name="wallet_title" msgid="5369767670735827105">"Դրամապանակ"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Պատրաստ է"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Ավելացնել վճարման եղանակ"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ապակողպել՝ օգտագործելու համար"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Չհաջողվեց բեռնել քարտերը։ Նորից փորձեք։"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Android for Work-ի պրոֆիլ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Ավիառեժիմ"</string>
<string name="add_tile" msgid="6239678623873086686">"Սալիկի ավելացում"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Կարգավիճակը․</b> իջեցվել է և դարձել անձայն"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Կարգավիճակը․</b> կարևորության մակարդակը բարձրացվել է"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Կարգավիճակը․</b> կարևորության մակարդակն իջեցվել է"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Այն միշտ ցուցադրվում է ձեր ծանուցումների վերևում, անգամ եթե միացված է առաջնահերթության ռեժիմը։"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Կարգավորումներ"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Կարևոր զրույցներ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ծանուցումների տվյալ խումբը հնարավոր չէ կարգավորել այստեղ"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Թարմացրեք համակարգի նավիգացիան կարգավորումներում"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Սպասման ռեժիմ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Զրույցը նշված է որպես կարևոր"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Կարևոր զրույցներ"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Այս զրույցները ցուցադրվում են ցանկի վերևում, և դուք կարող եք դրանք կարդալ, անգամ եթե միացված է առաջնահերթության ռեժիմը։"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Պրոֆիլի նկարները ցուցադրվում են կողպէկրանին"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Այս զրույցները կարող եք գտնել ամպիկներում՝ ձեր հիմնական էկրանին"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ընդհատել «Չանհանգստացնել» ռեժիմը"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Եղավ"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Կարգավորումներ"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Կոճակը ժամանակավորապես թաքցնելու համար այն տեղափոխեք էկրանի եզր"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Տեղափոխել վերև՝ ձախ"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Տեղափոխել վերև՝ աջ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Տեղափոխել ներքև՝ ձախ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Տեղափոխել ներքև՝ աջ"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Տեղափոխել եզրից դուրս և թաքցնել"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Տեղափոխել եզրից դուրս և ցուցադրել"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Սարքերի կառավարման տարրեր"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ավելացրեք կառավարման տարրեր ձեր միացված սարքերի համար"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Սարքերի կառավարման տարրերի կարգավորում"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Առավելագույնը <xliff:g id="DURATION">%1$s</xliff:g> առաջ"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Ավելի քան <xliff:g id="DURATION">%1$s</xliff:g> առաջ"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ծննդյան օր"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Այսօր <xliff:g id="NAME">%1$s</xliff:g>-ի տարեդարձն է"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Շուտով ծննդյանս օրն է"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Շուտով <xliff:g id="NAME">%1$s</xliff:g>-ի տարեդարձն է"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Տարեդարձ"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Այսօր <xliff:g id="NAME">%1$s</xliff:g>-ի տարեդարձն է"</string>
<string name="location_status" msgid="1294990572202541812">"Տեղադրության ցուցադրում"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը հայտնում է իր տեղադրության մասին տվյալները"</string>
<string name="new_story_status" msgid="9012195158584846525">"Նոր հոդված"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը նոր պատմություն է հրապարակել"</string>
<string name="video_status" msgid="4548544654316843225">"Տեսանյութ եմ դիտում"</string>
<string name="audio_status" msgid="4237055636967709208">"Բան եմ լսում"</string>
<string name="game_status" msgid="1340694320630973259">"Խաղ եմ խաղում"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Ընկերներ"</string>
<string name="empty_status" msgid="5938893404951307749">"Արի այսօր զրուցենք"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Բովանդակությունը շուտով կհայտնվի"</string>
<string name="missed_call" msgid="4228016077700161689">"Բաց թողնված զանգ"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Տեսեք վերջին հաղորդագրությունները, բաց թողնված զանգերը և կարգավիճակի մասին թարմացումները"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Զրույց"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը հաղորդագրություն է ուղարկել"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը պատկեր է ուղարկել"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչի ցուցմունքը կարդալու հետ կապված խնդիր կա"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Հպեք՝ ավելին իմանալու համար"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Զարթուցիչ դրված չէ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2f2385c..102c592 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Rekam lagi"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Menutup screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pratinjau screenshot"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Batas atas"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Batas bawah"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Perekam Layar"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifikasi yang sedang berjalan untuk sesi rekaman layar"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metode Masukan"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokasi Nonaktif"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokir Kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Bisukan Mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Akses kamera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Akses mikrofon"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tersedia"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Diblokir"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Perangkat media"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Panggilan Darurat Saja"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rekaman Layar"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mulai"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Untuk melanjutkan, <b><xliff:g id="APP">%s</xliff:g></b> memerlukan akses ke mikrofon perangkat."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Untuk melanjutkan, <b><xliff:g id="APP">%s</xliff:g></b> memerlukan akses ke kamera perangkat."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Batalkan pemblokiran mikrofon perangkat?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Batalkan pemblokiran kamera perangkat?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Batalkan pemblokiran kamera dan mikrofon perangkat?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ini akan membatalkan pemblokiran akses untuk semua aplikasi dan layanan yang diizinkan menggunakan mikrofon."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ini akan membatalkan pemblokiran akses untuk semua aplikasi dan layanan yang diizinkan menggunakan kamera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ini akan membatalkan pemblokiran akses untuk semua aplikasi dan layanan yang diizinkan menggunakan kamera atau mikrofon."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Perangkat"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Geser ke atas untuk beralih aplikasi"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tarik ke kanan untuk beralih aplikasi dengan cepat"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Siap"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Siapkan pembayaran"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Terjadi masalah saat mendapatkan kartu Anda, coba lagi nanti"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string>
<string name="add_tile" msgid="6239678623873086686">"Tambahkan ubin"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Didemosikan menjadi Senyap"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> Diberi Peringkat Lebih Tinggi"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> Diberi Peringkat Lebih Rendah"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Selalu tampilkan di notifikasi paling atas, meski Mode prioritas aktif"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setelan"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Percakapan prioritas"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Grup notifikasi ini tidak dapat dikonfigurasi di sini"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Buka Setelan untuk mengupdate navigasi sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Siaga"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Percakapan ditetapkan jadi prioritas"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Percakapan prioritas"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Percakapan ini akan ditampilkan di daftar paling atas dan selalu ditampilkan untuk Anda saat Mode prioritas aktif"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Foto profil ditampilkan di layar kunci"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Anda dapat mudah menemukan percakapan ini dalam balon di Layar utama"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Mengganggu fitur Jangan Ganggu"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Oke"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Setelan"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Alihkan"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tombol aksesibilitas menggantikan gestur aksesibilitas\n\n"<annotation id="link">"Tampilkan setelan"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pindahkan tombol ke tepi agar tersembunyi untuk sementara"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pindahkan ke kiri atas"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pindahkan ke kanan atas"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Pindahkan ke kiri bawah"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Pindahkan ke kanan bawah"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pindahkan ke tepi dan sembunyikan"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pindahkan dari tepi dan tampilkan"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrol perangkat"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambahkan kontrol untuk perangkat terhubung"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Siapkan kontrol perangkat"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Kurang dari <xliff:g id="DURATION">%1$s</xliff:g> yang lalu"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Lebih dari <xliff:g id="DURATION">%1$s</xliff:g> yang lalu"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ulang Tahun"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Hari ini ulang tahun <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Ulang tahun segera"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Ulang tahun <xliff:g id="NAME">%1$s</xliff:g> sebentar lagi"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Hari Peringatan"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Hari ini hari jadi <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Berbagi lokasi"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> sedang membagikan lokasi"</string>
<string name="new_story_status" msgid="9012195158584846525">"Story baru"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> membagikan story baru"</string>
<string name="video_status" msgid="4548544654316843225">"Menonton"</string>
<string name="audio_status" msgid="4237055636967709208">"Mendengarkan"</string>
<string name="game_status" msgid="1340694320630973259">"Bermain"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Teman"</string>
<string name="empty_status" msgid="5938893404951307749">"Ayo chat malam ini."</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Konten akan segera muncul"</string>
<string name="missed_call" msgid="4228016077700161689">"Panggilan tak terjawab"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Melihat pesan terbaru, panggilan tak terjawab, dan pembaruan status"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Percakapan"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> mengirim pesan"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> mengirim gambar"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi masalah saat membaca indikator baterai"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketuk untuk informasi selengkapnya"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm tidak disetel"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 6d412ec..8fe7b94 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Mynda meira"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Loka skjámynd"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forskoðun skjámyndar"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Efri mörk"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Neðri mörk"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skjáupptaka"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Innsláttaraðferð"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Staðsetning"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Staðsetning óvirk"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Loka á myndavél"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Slökkva á hljóðnema"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Aðgangur að myndavél"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Aðgangur að hljóðnema"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tiltækt"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Lokað á"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Margmiðlunartæki"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Aðeins neyðarsímtöl"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skjáupptaka"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hefja"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stöðva"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Til að halda áfram þarf <b><xliff:g id="APP">%s</xliff:g></b> aðgang að hljóðnema tækisins."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Til að halda áfram þarf <b><xliff:g id="APP">%s</xliff:g></b> aðgang að myndavél tækisins."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Opna fyrir hljóðnema tækisins?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Opna fyrir myndavél tækisins?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Opna fyrir myndavél og hljóðnema tækisins?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Þetta veitir öllum forritum og þjónustum aðgang að hljóðnemanum þínum."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Þetta veitir öllum forritum og þjónustum aðgang að myndavélinni þinni."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Þetta veitir öllum forritum og þjónustum aðgang að myndavélinni og hljóðnemanum þínum."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Tæki"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Strjúktu upp til að skipta á milli forrita"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Dragðu til hægri til að skipta hratt á milli forrita"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Vekjari"</string>
<string name="wallet_title" msgid="5369767670735827105">"Veski"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Tilbúið"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Setja upp greiðslu"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Taktu úr lás til að nota"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Vandamál kom upp við að sækja kortin þín. Reyndu aftur síðar"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Vinnusnið"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flugstilling"</string>
<string name="add_tile" msgid="6239678623873086686">"Bæta reit við"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Staða:</b> var gerð þögul"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Staða:</b> fékk hærri stöðu"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Staða:</b> fékk lægri stöðu"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Sýna alltaf efst í tilkynningum þó svo að kveikt sé á forgangsstillingu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Áfram"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Forgangssamtöl"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ekki er hægt að stilla þessar tilkynningar hér"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Farðu í stillingar til að uppfæra kerfisstjórnun"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Samtal sett í forgang"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Forgangssamtöl"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Þessi samtöl birtast efst á listanum og þú getur alltaf séð þau þegar kveikt er á forgangsstillingu"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Prófílmyndir birtast á lásskjánum"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Þú finnur samtölin auðveldlega í blöðrum á heimaskjánum þínum"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Stöðva „Ónáðið ekki“"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ég skil"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Stillingar"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Rofi"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Aðgengishnappur kom í stað aðgengisbendingar\n\n"<annotation id="link">"Skoða stillingar"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Færðu hnappinn að brúninni til að fela hann tímabundið"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Færa efst til vinstri"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Færa efst til hægri"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Færa neðst til vinstri"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Færa neðst til hægri"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Færa að jaðri og fela"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Færa að jaðri og birta"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Tækjastjórnun"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Bæta við stýringum fyrir tengd tæki"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Setja upp tækjastjórnun"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Fyrir minna en <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Fyrir meira en <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Afmæli"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> á afmæli"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Afmæli á næstunni"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> á bráðum afmæli"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Brúðkaupsafmæli"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> á brúðkaupsafmæli"</string>
<string name="location_status" msgid="1294990572202541812">"Deilir staðsetningu"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> deilir staðsetningu sinni"</string>
<string name="new_story_status" msgid="9012195158584846525">"Ný frétt"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> deildi nýrri sögu"</string>
<string name="video_status" msgid="4548544654316843225">"Að horfa"</string>
<string name="audio_status" msgid="4237055636967709208">"Hlustar"</string>
<string name="game_status" msgid="1340694320630973259">"Spilar"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Vinir"</string>
<string name="empty_status" msgid="5938893404951307749">"Spjöllum í kvöld!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Efnið birtist brátt"</string>
<string name="missed_call" msgid="4228016077700161689">"Ósvarað símtal"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Sjá nýleg skilboð, ósvöruð símtöl og stöðuuppfærslur"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Samtal"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> sendi skilaboð"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sendi mynd"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Vandamál við að lesa stöðu rafhlöðu"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ýttu til að fá frekari upplýsingar"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Enginn vekjari"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index e46ce8d..c3f4f69 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Acquisisci di più"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Anteprima screenshot"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Limite superiore"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Limite inferiore"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Registrazione dello schermo"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaboraz. registraz. schermo"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metodo di immissione"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Geolocalizzazione"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Geolocalizz. non attiva"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blocca la fotocamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Disattiva il microfono"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accesso alla fotocamera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Accesso al microfono"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponibile"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloccato"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimediale"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Solo chiamate di emergenza"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Registrazione schermo"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inizia"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Interrompi"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Per continuare, l\'app <b><xliff:g id="APP">%s</xliff:g></b> deve accedere al microfono del dispositivo."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Per continuare, l\'app <b><xliff:g id="APP">%s</xliff:g></b> deve accedere alla videocamera del dispositivo."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vuoi sbloccare il microfono del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vuoi sbloccare la fotocamera del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vuoi sbloccare la fotocamera e il microfono del dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare il microfono."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare la fotocamera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Viene sbloccato l\'accesso per tutti i servizi e le app autorizzati a usare la fotocamera o il microfono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Scorri verso l\'alto per passare ad altre app"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Trascina verso destra per cambiare velocemente app"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Sveglia"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Pronto"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configura un metodo di pagamento"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Sblocca per usare"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Si è verificato un problema durante il recupero delle tue carte. Riprova più tardi."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profilo di lavoro"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modalità aereo"</string>
<string name="add_tile" msgid="6239678623873086686">"Aggiungi riquadro"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stato:</b> retrocessa a Silenziosa"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Stato:</b> posizionata più in alto"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Stato:</b> posizionata più in basso"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Queste conversazioni vengono mostrate sempre in cima alle notifiche, anche quando la modalità Priorità è attiva"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Impostazioni"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversazioni prioritarie"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Usa le Impostazioni per aggiornare la navigazione del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Conversazione impostata come prioritaria"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversazioni prioritarie"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Queste conversazioni si trovano in cima all\'elenco e possono essere sempre mostrate quando la modalità Priorità è attiva"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Le immagini del profilo vengono mostrate nella schermata di blocco"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Puoi trovare facilmente queste conversazioni all\'interno di bolle nella schermata Home"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompono la modalità Non disturbare"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Impostazioni"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Opzione"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Il pulsante Accessibilità ha sostituito il gesto di accessibilità\n\n"<annotation id="link">"Visualizza le impostazioni"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sposta il pulsante fino al bordo per nasconderlo temporaneamente"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sposta in alto a sinistra"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sposta in alto a destra"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Sposta in basso a sinistra"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Sposta in basso a destra"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sposta fino a bordo e nascondi"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sposta fuori da bordo e mostra"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controllo dei dispositivi"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Aggiungi controlli per i dispositivi connessi"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura il controllo dei dispositivi"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Meno di <xliff:g id="DURATION">%1$s</xliff:g> fa"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Più di <xliff:g id="DURATION">%1$s</xliff:g> fa"</string>
<string name="birthday_status" msgid="2596961629465396761">"Compleanno"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"È il compleanno di <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Compleanno imminente"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"A breve sarà il compleanno di <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Anniversario"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"È l\'anniversario di <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Condivis. posizione"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> sta condividendo la posizione"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nuova notizia"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ha condiviso una nuova storia"</string>
<string name="video_status" msgid="4548544654316843225">"Visione in corso"</string>
<string name="audio_status" msgid="4237055636967709208">"Ascolto in corso"</string>
<string name="game_status" msgid="1340694320630973259">"Gioco in corso"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amici"</string>
<string name="empty_status" msgid="5938893404951307749">"Chattiamo stasera."</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"I contenuti verranno mostrati a breve"</string>
<string name="missed_call" msgid="4228016077700161689">"Chiamata persa"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Visualizza messaggi recenti, chiamate senza risposta e aggiornamenti dello stato"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversazione"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un messaggio"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un\'immagine"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema durante la lettura dell\'indicatore di livello della batteria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tocca per ulteriori informazioni"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nessuna sveglia"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 4ba43e1..67d47ae 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"צילום תוכן נוסף"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"סגירת צילום מסך"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"הקצה העליון"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"הקצה התחתון"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"שיטת קלט"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"מיקום"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"המיקום מושבת"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"חסימת המצלמה"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"השתקת המיקרופון"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"גישה למצלמה"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"גישה למיקרופון"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"יש גישה"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"הגישה חסומה"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"מכשיר מדיה"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"שיחות חירום בלבד"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"הקלטת המסך"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"התחלה"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"עצירה"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"כדי להמשיך, האפליקציה <b><xliff:g id="APP">%s</xliff:g></b> צריכה גישה למיקרופון של המכשיר שלך."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"כדי להמשיך, האפליקציה <b><xliff:g id="APP">%s</xliff:g></b> צריכה גישה למצלמה של המכשיר שלך."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"לבטל את חסימת המיקרופון של המכשיר?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"לבטל את חסימת המצלמה של המכשיר?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"לבטל את חסימת המצלמה והמיקרופון של המכשיר?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במיקרופון."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במצלמה."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"הפעולה הזו מבטלת את חסימת הגישה של כל האפליקציות והשירותים שמורשים להשתמש במצלמה או במיקרופון."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"מכשיר"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"יש להחליק מעלה כדי להחליף אפליקציות"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"יש לגרור ימינה כדי לעבור במהירות בין אפליקציות"</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"אתרנט"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"התראה"</string>
<string name="wallet_title" msgid="5369767670735827105">"ארנק"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"מוכן"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"הגדרת אמצעי התשלום"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"יש לבטל את הנעילה כדי להשתמש"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"הייתה בעיה בקבלת הכרטיסים שלך. כדאי לנסות שוב מאוחר יותר"</string>
<string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string>
<string name="add_tile" msgid="6239678623873086686">"הוספת אריח"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>הסטטוס:</b> הורד בדרגה ל\'שקט\'"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>הסטטוס:</b> דורג גבוה יותר"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>הסטטוס:</b> דורג נמוך יותר"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"תמיד מוצגות בראש ההתראות, גם כשמצב העדיפות פועל"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"הגדרות"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"שיחות בעדיפות גבוהה"</string>
<string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"לא ניתן להגדיר כאן את קבוצת ההתראות הזו"</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"השיחה הוגדרה כבעלת עדיפות גבוהה"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"שיחות בעדיפות גבוהה"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"השיחות האלה מוצגות בראש הרשימה והן יופיעו כל עוד מצב העדיפות פועל"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"תמונות הפרופיל מוצגות במסך הנעילה"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"קל למצוא את השיחות האלה בבועות המופיעות במסך הבית"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"גוברות על ההגדרה \'נא לא להפריע\'"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"הבנתי"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"הגדרות"</string>
@@ -1050,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"כדי להסתיר זמנית את הלחצן, יש להזיז אותו לקצה"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"העברה לפינה השמאלית העליונה"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"העברה לפינה הימנית העליונה"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"העברה לפינה השמאלית התחתונה"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"העברה לפינה הימנית התחתונה"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"העברה לשוליים והסתרה"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"העברה מהשוליים והצגה"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"פקדי מכשירים"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"יש להוסיף פקדים למכשירים המחוברים"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"הגדרה של פקדי מכשירים"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"לפני פחות מ-<xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"לפני יותר מ-<xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"יום הולדת"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"זהו יום ההולדת של <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"יום הולדת יחול בקרוב"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"יום ההולדת של <xliff:g id="NAME">%1$s</xliff:g> מתקרב"</string>
<string name="anniversary_status" msgid="1790034157507590838">"יום השנה"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"זהו יום הנישואין של <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"המיקום משותף"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> משתף/ת את פרטי המיקום"</string>
<string name="new_story_status" msgid="9012195158584846525">"סטורי חדש"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> שיתף/ה סטורי חדש"</string>
<string name="video_status" msgid="4548544654316843225">"צפייה"</string>
<string name="audio_status" msgid="4237055636967709208">"מתבצעת האזנה"</string>
<string name="game_status" msgid="1340694320630973259">"במשחק פעיל"</string>
<string name="empty_user_name" msgid="3389155775773578300">"חברים"</string>
<string name="empty_status" msgid="5938893404951307749">"אפשר לצ\'וטט הערב!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"התוכן יוצג בקרוב"</string>
<string name="missed_call" msgid="4228016077700161689">"שיחה שלא נענתה"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ההודעות האחרונות, שיחות שלא נענו ועדכוני סטטוס"</string>
<string name="people_tile_title" msgid="6589377493334871272">"שיחה"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> שלח/ה הודעה"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> שלח/ה תמונה"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"לא הוגדרה התראה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d646f05..1db068f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"キャプチャ範囲を拡大"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"スクリーンショットを閉じます"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"スクリーンショットのプレビュー"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"上部境界"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"下部境界"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"スクリーン レコーダー"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"画面の録画を処理しています"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"画面の録画セッション中の通知"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"入力方法"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置情報"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"現在地OFF"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"カメラをブロック"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"マイクをミュート"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"カメラへのアクセス"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"マイクへのアクセス"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"使用可能"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ブロック中"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"メディアデバイス"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"緊急通報のみ"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"スクリーン レコード"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"続行するには、<b><xliff:g id="APP">%s</xliff:g></b> にデバイスのマイクへのアクセスを許可する必要があります。"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"続行するには、<b><xliff:g id="APP">%s</xliff:g></b> にデバイスのカメラへのアクセスを許可する必要があります。"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"デバイスのマイクのブロックを解除しますか?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"デバイスのカメラのブロックを解除しますか?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"デバイスのカメラとマイクのブロックを解除しますか?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"マイクの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"カメラの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"カメラやマイクの使用が許可されているすべてのアプリとサービスでアクセスのブロックが解除されます。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"デバイス"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"アプリを切り替えるには上にスワイプ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"右にドラッグするとアプリを素早く切り替えることができます"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"イーサネット"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"アラーム"</string>
<string name="wallet_title" msgid="5369767670735827105">"ウォレット"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"準備完了"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"お支払いの設定"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ロックを解除して使用"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"カードの取得中に問題が発生しました。しばらくしてからもう一度お試しください"</string>
<string name="status_bar_work" msgid="5238641949837091056">"仕事用プロファイル"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"機内モード"</string>
<string name="add_tile" msgid="6239678623873086686">"タイルを追加"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ステータス:</b> ランクがサイレントに下がりました"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>ステータス:</b> ランクが上がりました"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>ステータス:</b> ランクが下がりました"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"優先モードが ON の場合でも、常に通知の一番上に表示されます"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"優先度の高い会話"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> は会話機能に対応していません"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"このグループの通知はここでは設定できません"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"システム ナビゲーションを更新するには [設定] に移動してください"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"優先度を高く設定された会話"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"優先度の高い会話"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"優先モードが ON の場合、これらの会話はリストの一番上に表示されるのでいつでも確認できます"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"プロフィール写真がロック画面に表示されます"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"これらの会話はホーム画面のバブル内で簡単に確認できます"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"サイレント モードが ON でも表示"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ボタンを一時的に非表示にするには端に移動させてください"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"左上に移動"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"右上に移動"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"左下に移動"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"右下に移動"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"端に移動して非表示"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"端から移動して表示"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"接続済みデバイスのコントロールを追加します"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"デバイス コントロールの設定"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>前まで"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>以上前"</string>
<string name="birthday_status" msgid="2596961629465396761">"誕生日"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"今日は <xliff:g id="NAME">%1$s</xliff:g> さんのお誕生日です"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"もうすぐ誕生日"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"まもなく <xliff:g id="NAME">%1$s</xliff:g> さんのお誕生日です"</string>
<string name="anniversary_status" msgid="1790034157507590838">"記念日"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"今日は <xliff:g id="NAME">%1$s</xliff:g> さんの記念日です"</string>
<string name="location_status" msgid="1294990572202541812">"現在地を共有中"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> さんが位置情報を共有しています"</string>
<string name="new_story_status" msgid="9012195158584846525">"新しいストーリー"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> さんが新しいストーリーを共有しました"</string>
<string name="video_status" msgid="4548544654316843225">"視聴中"</string>
<string name="audio_status" msgid="4237055636967709208">"再生中"</string>
<string name="game_status" msgid="1340694320630973259">"プレイ中"</string>
<string name="empty_user_name" msgid="3389155775773578300">"友だち"</string>
<string name="empty_status" msgid="5938893404951307749">"今夜、チャットしよう"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"まもなく会話の内容が表示されます"</string>
<string name="missed_call" msgid="4228016077700161689">"不在着信"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g> 件以上"</string>
<string name="people_tile_description" msgid="8154966188085545556">"最近のメッセージ、不在着信、最新のステータスが表示されます"</string>
<string name="people_tile_title" msgid="6589377493334871272">"会話"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> さんからメッセージが届きました"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> さんが画像を送信しました"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"電池残量の読み込み中に問題が発生しました"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"アラーム未設定"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 6461837..f529abf 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"მეტის აღბეჭდვა"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ეკრანის ანაბეჭდის დახურვა"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ეკრანის ანაბეჭდის გადახედვა"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ზედა საზღვარი"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ქვედა საზღვარი"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ეკრანის ჩამწერი"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ეკრანის ჩანაწერი მუშავდება"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"უწყვეტი შეტყობინება ეკრანის ჩაწერის სესიისთვის"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"შეყვანის მეთოდი"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"მდებარეობა"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"მდებარეობა გამორთულია"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"კამერის დაბლოკვა"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"მიკროფონის დადუმება"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"კამერაზე წვდომა"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"მიკროფონზე წვდომა"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ხელმისაწვდომი"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"დაბლოკილი"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"მედია მოწყობილობა"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"მხოლოდ გადაუდებელი დახმარების ზარებისთვის"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ეკრანის ჩანაწერი"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"დაწყება"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"შეწყვეტა"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"გასაგრძელებლად <b><xliff:g id="APP">%s</xliff:g></b>-ს თქვენი მოწყობილობის მიკროფონზე წვდომა სჭირდება."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"გასაგრძელებლად <b><xliff:g id="APP">%s</xliff:g></b>-ს თქვენი მოწყობილობის კამერაზე წვდომა სჭირდება."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"გსურთ მოწყობილობის კამერის განბლოკვა?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"გსურთ მოწყობილობის კამერის და მიკროფონის განბლოკვა?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი მიკროფონის გამოყენების უფლება."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი კამერის გამოყენების უფლება."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ამ მოქმედების მეშვეობით განიბლოკება ყველა აპსა და მომსახურებაზე წვდომა, რომელთაც აქვთ თქვენი კამერის ან მიკროფონის გამოყენების უფლება."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"მოწყობილობა"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"გადაფურცლეთ ზემოთ აპების გადასართავად"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"აპების სწრაფად გადასართავად ჩავლებით გადაიტანეთ მარჯვნივ"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ეთერნეტი"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"მაღვიძარა"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"ყველას ჩვენება"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"გადასახდელად განბლოკვა"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"მზადაა"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"გადახდის დაყენება"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"გამოსაყენებლად განბლოკვა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 37f6545..da3edb1b 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Тағы суретке түсіру"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотты жабу"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотты алдын ала қарау"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Жоғарғы шектік сызық"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Төменгі шектік сызық"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Экран жазғыш"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Енгізу әдісі"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Орын өшірулі"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Камераны бөгеу"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Микрофон дыбысын өшіру"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Камераны пайдалану рұқсаты"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофонды пайдалану рұқсаты"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Қолжетімді"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Бөгелген"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Meдиа құрылғысы"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI (алынған сигнал қуатының көрсеткіші)"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Құтқару қызметіне ғана қоңырау шалынады"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Экранды жазу"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Бастау"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Тоқтату"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Жалғастыру үшін <b><xliff:g id="APP">%s</xliff:g></b> қолданбасы құрылғыңыздың микрофонына рұқсат алу керек."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Жалғастыру үшін <b><xliff:g id="APP">%s</xliff:g></b> қолданбасы құрылғыңыздың камерасына рұқсат алу керек."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Құрылғы микрофонының бөгеуі алынсын ба?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Құрылғы камерасының бөгеуі алынсын ба?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Құрылғы камерасы мен микрофонының бөгеуі алынсын ба?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Микрофоныңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Камераңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Камераңызды немесе микрофоныңызды пайдалануға рұқсат берілген барлық қолданба мен қызметтің бөгеуі алынады."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Құрылғы"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Қолданбалар арасында ауысу үшін жоғары сырғытыңыз"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Қолданбаларды жылдам ауыстырып қосу үшін оңға қарай сүйреңіз"</string>
@@ -508,7 +520,7 @@
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Үнсіз"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Хабарландырулар"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string>
- <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Барлық дыбыссыз хабарландыруларды өшіру"</string>
+ <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Барлық үнсіз хабарландыруларды өшіру"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Хабарландырулар Мазаламау режимінде кідіртілді"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Қазір бастау"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Хабарландырулар жоқ"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Дабыл"</string>
<string name="wallet_title" msgid="5369767670735827105">"Әмиян"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Дайын"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Төлем әдісін реттеу"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Пайдалану үшін құлыпты ашу"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Карталарыңыз алынбады, кейінірек қайталап көріңіз."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string>
<string name="add_tile" msgid="6239678623873086686">"Тақтайша қосу"</string>
@@ -707,7 +715,7 @@
<string name="notification_header_default_channel" msgid="225454696914642444">"Хабарландырулар"</string>
<string name="notification_channel_disabled" msgid="928065923928416337">"Хабарландырулар бұдан былай көрсетілмейді"</string>
<string name="notification_channel_minimized" msgid="6892672757877552959">"Хабарландырулар жасырылады"</string>
- <string name="notification_channel_silenced" msgid="1995937493874511359">"Бұл хабарландырулар дыбыссыз көрсетіледі"</string>
+ <string name="notification_channel_silenced" msgid="1995937493874511359">"Бұл хабарландырулар үнсіз көрсетіледі"</string>
<string name="notification_channel_unsilenced" msgid="94878840742161152">"Бұл хабарландырулар сізді ескертеді"</string>
<string name="inline_blocking_helper" msgid="2891486013649543452">"Әдетте хабарландыруларды көрмейсіз. \nОлар көрсетілсін бе?"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Дайын"</string>
@@ -718,13 +726,13 @@
<string name="inline_block_button" msgid="479892866568378793">"Бөгеу"</string>
<string name="inline_keep_button" msgid="299631874103662170">"Көрсету"</string>
<string name="inline_minimize_button" msgid="1474436209299333445">"Жасыру"</string>
- <string name="inline_silent_button_silent" msgid="525243786649275816">"Дыбыссыз"</string>
+ <string name="inline_silent_button_silent" msgid="525243786649275816">"Үнсіз"</string>
<string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"Хабарландырулар алғым келмейді"</string>
<string name="inline_silent_button_alert" msgid="5705343216858250354">"Ескерту"</string>
<string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"Хабарландырулар келе берсін"</string>
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Хабарландыруларды өшіру"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Осы қолданбаның хабарландырулары көрсетілсін бе?"</string>
- <string name="notification_silence_title" msgid="8608090968400832335">"Дыбыссыз"</string>
+ <string name="notification_silence_title" msgid="8608090968400832335">"Үнсіз"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Әдепкі"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматты"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дыбыс не діріл қолданылмайды"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Күйі:</b> \"Үнсіз\" санатына төмендетілген"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Күйі:</b> маңыздылық деңгейі көтерілген"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Күйі:</b> маңыздылық деңгейі төмендетілген"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Әрдайым (тіпті \"Маңызды\" режимі қосулы болса да) хабарландыруларыңыздың жоғарғы жағында көрсетіледі"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Маңызды чаттар"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгімелесу функцияларын қолдамайды."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string>
@@ -865,7 +871,7 @@
<item msgid="2681220472659720036">"Буфер"</item>
<item msgid="4795049793625565683">"Перне коды"</item>
<item msgid="80697951177515644">"Айналдыруды растау, пернетақта ауыстырғыш"</item>
- <item msgid="7626977989589303588">"Ешқандай"</item>
+ <item msgid="7626977989589303588">"Жоқ"</item>
</string-array>
<string-array name="nav_bar_layouts">
<item msgid="9156773083127904112">"Орташа"</item>
@@ -941,7 +947,7 @@
<string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Оң жақ таңбаша"</string>
<string name="lockscreen_unlock_left" msgid="1417801334370269374">"Сол жақ таңбаша құлыпты ашады"</string>
<string name="lockscreen_unlock_right" msgid="4658008735541075346">"Оң жақ таңбаша құлыпты ашады"</string>
- <string name="lockscreen_none" msgid="4710862479308909198">"Ешқандай"</string>
+ <string name="lockscreen_none" msgid="4710862479308909198">"Жоқ"</string>
<string name="tuner_launch_app" msgid="3906265365971743305">"<xliff:g id="APP">%1$s</xliff:g> қолданбасын іске қосу"</string>
<string name="tuner_other_apps" msgid="7767462881742291204">"Басқа қолданбалар"</string>
<string name="tuner_circle" msgid="5270591778160525693">"Шеңбер"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Жүйе навигациясын жаңарту үшін \"Параметрлер\" бөліміне өтіңіз."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Әңгіме маңызды деп белгіленді"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Маңызды чаттар"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Бұл чаттар тізіміңіздің жоғарғы жағында көрсетіледі және \"Маңызды\" режимі қосулы болған кезде әрдайым қолжетімді болады."</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Профиль суреттері құлыптаулы экранда көрсетіледі."</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Бұл чаттарды негізгі экрандағы қалқыма хабарлардан оңай таба аласыз."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Мазаламау режимінде көрсетіледі."</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Түсінікті"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Параметрлер"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Түймені уақытша жасыру үшін оны шетке қарай жылжытыңыз."</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жоғарғы сол жаққа жылжыту"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жоғарғы оң жаққа жылжыту"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Төменгі сол жаққа жылжыту"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Төменгі оң жаққа жылжыту"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Шетке жылжыту және жасыру"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Шетке жылжыту және көрсету"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Жалғанған құрылғылар үшін басқару виджеттерін қосу"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Құрылғыны басқару элементтерін реттеу"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Максимум <xliff:g id="DURATION">%1$s</xliff:g> бұрын"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Кемінде <xliff:g id="DURATION">%1$s</xliff:g> бұрын"</string>
<string name="birthday_status" msgid="2596961629465396761">"Туған күн"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Бүгін <xliff:g id="NAME">%1$s</xliff:g> туған күнін атап өтуде!"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Жақында туған күн"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Жақында <xliff:g id="NAME">%1$s</xliff:g> туған күнін атап өтеді."</string>
<string name="anniversary_status" msgid="1790034157507590838">"Мерейтой"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Бүгін <xliff:g id="NAME">%1$s</xliff:g> мерейтойын атап өтуде!"</string>
<string name="location_status" msgid="1294990572202541812">"Геодеректер жіберілуде"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> локациясын бөлісуде."</string>
<string name="new_story_status" msgid="9012195158584846525">"Жаңа сюжет"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> жаңа сюжетін бөлісті."</string>
<string name="video_status" msgid="4548544654316843225">"Көрілуде"</string>
<string name="audio_status" msgid="4237055636967709208">"Тыңдалуда"</string>
<string name="game_status" msgid="1340694320630973259">"Ойнатылуда"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Достар"</string>
<string name="empty_status" msgid="5938893404951307749">"Кешке чатта сөйлесейік!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Мазмұн жақында көрсетіледі."</string>
<string name="missed_call" msgid="4228016077700161689">"Өткізіп алған қоңырау"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Соңғы хабарларды, өткізіп алған қоңыраулар мен жаңартылған күйлерді көруге болады."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Әңгіме"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> хабар жіберді."</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сурет жіберді."</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батарея зарядының дерегі алынбай жатыр"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Толығырақ ақпарат алу үшін түртіңіз."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ешқандай оятқыш орнатылмаған."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index a0fb09a..f7f99c7 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ថតច្រើនទៀត"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ច្រានចោលរូបថតអេក្រង់"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ការមើលរូបថតអេក្រង់សាកល្បង"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"បន្ទាត់បែងចែកខាងលើ"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"បន្ទាត់បែងចែកខាងក្រោម"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថតអេក្រង់"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុងដំណើរការការថតអេក្រង់"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹងដែលកំពុងដំណើរការសម្រាប់រយៈពេលប្រើការថតសកម្មភាពអេក្រង់"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"វិធីសាស្ត្របញ្ចូល"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ទីតាំង"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ទីតាំងបានបិទ"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ទប់ស្កាត់កាមេរ៉ា"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"បិទសំឡេងមីក្រូហ្វូន"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"ការចូលប្រើកាមេរ៉ា"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"ការចូលប្រើមីក្រូហ្វូន"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"អាចប្រើបាន"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"បានទប់ស្កាត់"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ឧបករណ៍មេឌៀ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ការហៅទៅលេខសង្គ្រោះបន្ទាន់តែប៉ុណ្ណោះ"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ការថតអេក្រង់"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ចាប់ផ្ដើម"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ឈប់"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ដើម្បីបន្ត <b><xliff:g id="APP">%s</xliff:g></b> ត្រូវការសិទ្ធិចូលប្រើមីក្រូហ្វូនរបស់ឧបករណ៍អ្នក។"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ដើម្បីបន្ត <b><xliff:g id="APP">%s</xliff:g></b> ត្រូវការសិទ្ធិចូលប្រើកាមេរ៉ារបស់ឧបករណ៍អ្នក។"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ឈប់ទប់ស្កាត់មីក្រូហ្វូនរបស់ឧបករណ៍ឬ?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ឈប់ទប់ស្កាត់កាមេរ៉ារបស់ឧបករណ៍ឬ?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ឈប់ទប់ស្កាត់កាមេរ៉ា និងមីក្រូហ្វូនរបស់ឧបករណ៍ឬ?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើមីក្រូហ្វូនរបស់អ្នក។"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើកាមេរ៉ារបស់អ្នក។"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ការធ្វើបែបនេះនឹងឈប់ទប់ស្កាត់ការចូលប្រើសម្រាប់កម្មវិធី និងសេវាកម្មទាំងអស់ ដែលត្រូវបានអនុញ្ញាតឱ្យប្រើកាមេរ៉ា ឬមីក្រូហ្វូនរបស់អ្នក។"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ឧបករណ៍"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"អូសឡើងលើដើម្បីប្តូរកម្មវិធី"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"អូសទៅស្ដាំដើម្បីប្ដូរកម្មវិធីបានរហ័ស"</string>
@@ -498,7 +510,7 @@
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"បិទមុខងារសន្សំថ្ម"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬភ្ជាប់។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"សេវាកម្មដែលផ្ដល់មុខងារនេះនឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬភ្ជាប់។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string>
- <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ចាប់ផ្ដើមថត ឬបញ្ជូនមែនទេ?"</string>
+ <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ចាប់ផ្ដើមថត ឬភ្ជាប់មែនទេ?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"ចាប់ផ្ដើមថត ឬភ្ជាប់ដោយប្រើ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ឬ?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"កុំបង្ហាញម្ដងទៀត"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"សម្អាតទាំងអស់"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"អ៊ីសឺរណិត"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"ម៉ោងរោទ៍"</string>
<string name="wallet_title" msgid="5369767670735827105">"កាបូប"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"រួចរាល់"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"រៀបចំការបង់ប្រាក់"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ដោះសោដើម្បីប្រើប្រាស់"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"មានបញ្ហាក្នុងការទាញយកកាតរបស់អ្នក សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ"</string>
<string name="status_bar_work" msgid="5238641949837091056">"ប្រវត្តិរូបការងារ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"របៀបក្នុងយន្តហោះ"</string>
<string name="add_tile" msgid="6239678623873086686">"បន្ថែមក្រឡាល្អិត"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ស្ថានភាព៖</b> បានបញ្ចុះទៅស្ងាត់"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>ស្ថានភាព៖</b> បានចាត់ថ្នាក់ខ្ពស់ជាងមុន"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>ស្ថានភាព៖</b> បានចាត់ថ្នាក់ទាបជាងមុន"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"បង្ហាញនៅផ្នែកខាងលើការជូនដំណឹងរបស់អ្នកជានិច្ច ទោះបីជានៅពេលបើកមុខងារអាទិភាពក៏ដោយ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ការកំណត់"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"ការសន្ទនាអាទិភាព"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើមុខងារសន្ទនាបានទេ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាចកែប្រែការជូនដំណឹងទាំងនេះបានទេ។"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"មិនអាចកំណត់រចនាសម្ព័ន្ធក្រុមការជូនដំណឹងនេះនៅទីនេះបានទេ"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ចូលទៅកាន់ការកំណត់ ដើម្បីធ្វើបច្ចុប្បន្នភាពការរុករកក្នុងប្រព័ន្ធ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាកដំណើរការ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"បានកំណត់ការសន្ទនាជាអាទិភាព"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"ការសន្ទនាអាទិភាព"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ការសន្ទនាទាំងនេះបង្ហាញនៅផ្នែកខាងលើបញ្ជីរបស់អ្នក និងអាចបង្ហាញដល់អ្នកជានិច្ច នៅពេលបើកមុខងារអាទិភាព"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"រូបភាពកម្រងព័ត៌មានបង្ហាញនៅលើអេក្រង់ចាក់សោ"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"អ្នកអាចរកមើលការសន្ទនាទាំងនេះបានយ៉ាងងាយស្រួលនៅក្នុងពពុះនៅលើអេក្រង់ដើមរបស់អ្នក"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ផ្អាកមុខងារកុំរំខាន"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"យល់ហើយ"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ការកំណត់"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ផ្លាស់ទីប៊ូតុងទៅគែម ដើម្បីលាក់វាជាបណ្ដោះអាសន្ន"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងឆ្វេង"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងស្ដាំ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ផ្លាស់ទីទៅខាងក្រោមផ្នែកខាងឆ្វេង"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ផ្លាស់ទីទៅខាងក្រោមផ្នែកខាងស្ដាំ"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ផ្លាស់ទីទៅផ្នែកខាងចុង រួចលាក់"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ផ្លាស់ទីចេញពីផ្នែកខាងចុង រួចបង្ហាញ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"បញ្ចូលផ្ទាំងគ្រប់គ្រងសម្រាប់ឧបករណ៍ដែលអ្នកបានភ្ជាប់"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"រៀបចំផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"តិចជាង <xliff:g id="DURATION">%1$s</xliff:g> មុន"</string>
<string name="over_timestamp" msgid="4765793502859358634">"ជាង <xliff:g id="DURATION">%1$s</xliff:g> មុន"</string>
<string name="birthday_status" msgid="2596961629465396761">"ថ្ងៃកំណើត"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"នេះគឺជាថ្ងៃកំណើតរបស់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ថ្ងៃកំណើតឆាប់ៗនេះ"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"ថ្ងៃកំណើតរបស់ <xliff:g id="NAME">%1$s</xliff:g> នឹងចូលមកដល់ឆាប់ៗនេះ"</string>
<string name="anniversary_status" msgid="1790034157507590838">"គម្រប់ខួប"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"នេះគឺជាទិវាគម្រប់ខួបរបស់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"កំពុងចែករំលែកទីតាំង"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> កំពុងចែករំលែកទីតាំង"</string>
<string name="new_story_status" msgid="9012195158584846525">"រឿងថ្មី"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> បានចែករំលែករឿងថ្មី"</string>
<string name="video_status" msgid="4548544654316843225">"កំពុងមើល"</string>
<string name="audio_status" msgid="4237055636967709208">"កំពុងស្តាប់"</string>
<string name="game_status" msgid="1340694320630973259">"កំពុងលេង"</string>
<string name="empty_user_name" msgid="3389155775773578300">"មិត្តភ័ក្ដិ"</string>
<string name="empty_status" msgid="5938893404951307749">"តោះជជែកគ្នាយប់នេះ!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"ខ្លឹមសារនឹងបង្ហាញក្នុងពេលបន្តិចទៀត"</string>
<string name="missed_call" msgid="4228016077700161689">"ខកខានទទួល"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"មើលព័ត៌មានថ្មីៗអំពីស្ថានភាព ការខកខានទទួល និងសារថ្មីៗ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ការសន្ទនា"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើសារ"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើរូបភាព"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"មានបញ្ហាក្នុងការអានឧបករណ៍រង្វាស់កម្រិតថ្មរបស់អ្នក"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"មិនបានកំណត់ម៉ោងរោទ៍ទេ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0c10103..2f268d4 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ಇನ್ನಷ್ಟು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ಸ್ಕ್ರೀನ್ಶಾಟ್ನ ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ಮೇಲಿನ ಗಡಿರೇಖೆ"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ಕೆಳಗಿನ ಗಡಿರೇಖೆ"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡರ್"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೆಶನ್ಗಾಗಿ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಅಧಿಸೂಚನೆ"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ಇನ್ಪುಟ್ ವಿಧಾನ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ಸ್ಥಳ"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ಸ್ಥಳ ಆಫ್ ಆಗಿದೆ"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ಕ್ಯಾಮರಾವನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"ಮೈಕ್ರೋಫೋನ್ ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ಮಾಧ್ಯಮ ಸಾಧನ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ತುರ್ತು ಕರೆಗಳು ಮಾತ್ರ"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ನಿಲ್ಲಿಸಿ"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ಮುಂದುವರಿಯಲು, <b><xliff:g id="APP">%s</xliff:g></b> ಗೆ ನಿಮ್ಮ ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ನ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ಮುಂದುವರಿಯಲು, <b><xliff:g id="APP">%s</xliff:g></b> ಗೆ ನಿಮ್ಮ ಸಾಧನದ ಕ್ಯಾಮರಾದ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ."</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"ಸಾಧನ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಿಸಲು ತ್ವರಿತವಾಗಿ ಬಲಕ್ಕೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ಇಥರ್ನೆಟ್"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"ಅಲಾರಮ್"</string>
<string name="wallet_title" msgid="5369767670735827105">"ವಾಲೆಟ್"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"ಸಿದ್ಧವಾಗಿದೆ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ಪಾವತಿಯನ್ನು ಸೆಟಪ್ ಮಾಡಿ"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ಬಳಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"ನಿಮ್ಮ ಕಾರ್ಡ್ಗಳನ್ನು ಪಡೆಯುವಾಗ ಸಮಸ್ಯೆ ಉಂಟಾಗಿದೆ, ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್"</string>
<string name="add_tile" msgid="6239678623873086686">"ಟೈಲ್ ಸೇರಿಸಿ"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ಸ್ಥಿತಿ:</b> ಸೈಲೆಂಟ್ಗೆ ಕೆಳದರ್ಜೆಗೆ ಇಳಿದಿದೆ"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>ಸ್ಥಿತಿ:</b> ಉನ್ನತ ಸ್ಥಾನವನ್ನು ಹೊಂದಿದೆ"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>ಸ್ಥಿತಿ:</b> ಕಡಿಮೆ ಸ್ಥಾನವನ್ನು ಹೊಂದಿದೆ"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"ಆದ್ಯತಾ ಮೋಡ್ ಆನ್ ಆಗಿದ್ದರೂ ಸಹ, ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಯಾವಾಗಲೂ ತೋರಿಸಲಾಗುತ್ತದೆ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"ಆದ್ಯತೆಯ ಸಂಭಾಷಣೆಗಳು"</string>
<string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ಈ ಗುಂಪಿನ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇಲ್ಲಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿರುವುದಿಲ್ಲ"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್ಬೈ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"ಸಂವಾದವನ್ನು ಆದ್ಯತೆಯಾಗಿ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"ಆದ್ಯತೆಯ ಸಂಭಾಷಣೆಗಳು"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ಈ ಸಂಭಾಷಣೆಗಳನ್ನು ನಿಮ್ಮ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸಲಾಗಿದೆ ಮತ್ತು ಆದ್ಯತಾ ಮೋಡ್ ಆನ್ ಆಗಿರುವಾಗ ಯಾವಾಗಲೂ ನಿಮ್ಮನ್ನು ತಲುಪಬಹುದು"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"ಪ್ರೊಫೈಲ್ ಚಿತ್ರಗಳನ್ನು ಲಾಕ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ತೋರಿಸಲಾಗಿದೆ"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ನ ಬಬಲ್ಸ್ನಲ್ಲಿ ಈ ಸಂಭಾಷಣೆಗಳನ್ನು ನೀವು ಸುಲಭವಾಗಿ ಕಾಣಬಹುದು"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ಅಡಚಣೆ ಮಾಡಬೇಡ ಅನ್ನು ಅಡ್ಡಿಪಡಿಸಿ"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ಅರ್ಥವಾಯಿತು"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
@@ -1040,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ಅದನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ಮರೆಮಾಡಲು ಅಂಚಿಗೆ ಬಟನ್ ಸರಿಸಿ"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ಎಡ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ಸ್ಕ್ರೀನ್ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ಅಂಚಿಗೆ ಸರಿಸಿ ಮತ್ತು ಮರೆಮಾಡಿ"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ಅಂಚನ್ನು ಸರಿಸಿ ಮತ್ತು ತೋರಿಸಿ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ನಿಮ್ಮ ಸಂಪರ್ಕಿತ ಸಾಧನಗಳಿಗೆ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೆಟಪ್ ಮಾಡಿ"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> ಗಿಂತ ಕಡಿಮೆ ಅವಧಿಯ ಹಿಂದೆ"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> ಗಿಂತ ಹೆಚ್ಚಿನ ಅವಧಿಯ ಹಿಂದೆ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ಜನ್ಮದಿನ"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರ ಜನ್ಮದಿನ"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ಶೀಘ್ರದಲ್ಲಿ ಜನ್ಮದಿನವಿದೆ"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರ ಜನ್ಮದಿನ ಶೀಘ್ರದಲ್ಲೇ ಬರಲಿದೆ"</string>
<string name="anniversary_status" msgid="1790034157507590838">"ವಾರ್ಷಿಕೋತ್ಸವ"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರ ವಾರ್ಷಿಕೋತ್ಸವ"</string>
<string name="location_status" msgid="1294990572202541812">"ಸ್ಥಳ ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸ್ಥಳವನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತಿದ್ದಾರೆ"</string>
<string name="new_story_status" msgid="9012195158584846525">"ಹೊಸ ಸುದ್ದಿ"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಹೊಸ ಸ್ಟೋರಿಯನ್ನು ಹಂಚಿಕೊಂಡಿದ್ದಾರೆ"</string>
<string name="video_status" msgid="4548544654316843225">"ವೀಕ್ಷಿಸುತ್ತಿರುವವರು"</string>
<string name="audio_status" msgid="4237055636967709208">"ಆಲಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="game_status" msgid="1340694320630973259">"ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="empty_user_name" msgid="3389155775773578300">"ಸ್ನೇಹಿತರು"</string>
<string name="empty_status" msgid="5938893404951307749">"ಈ ರಾತ್ರಿ ಚಾಟ್ ಮಾಡೋಣ!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"ವಿಷಯ ಶೀಘ್ರದಲ್ಲೇ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ"</string>
<string name="missed_call" msgid="4228016077700161689">"ಮಿಸ್ಡ್ ಕಾಲ್"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ಇತ್ತೀಚಿನ ಸಂದೇಶಗಳು, ಮಿಸ್ಡ್ ಕಾಲ್ಗಳು ಮತ್ತು ಸ್ಥಿತಿ ಅಪ್ಡೇಟ್ಗಳು"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ಸಂಭಾಷಣೆ"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ಸಂದೇಶವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಮೀಟರ್ ಓದುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ಅಲಾರಾಂ ಸೆಟ್ ಆಗಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 5e71548..878b1a7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"더 캡처하기"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"스크린샷 닫기"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"스크린샷 미리보기"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"상단 경계"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"하단 경계"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"화면 녹화"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"입력 방법"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"위치"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"위치 사용 중지"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"카메라 차단"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"마이크 음소거"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"카메라 액세스"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"마이크 액세스"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"허용됨"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"차단됨"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"미디어 기기"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"긴급 통화만 허용"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"화면 녹화"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"시작"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"중지"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"계속하려면 <b><xliff:g id="APP">%s</xliff:g></b>에서 기기 마이크에 액세스해야 합니다."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"계속하려면 <b><xliff:g id="APP">%s</xliff:g></b>에서 기기 카메라에 액세스해야 합니다."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 차단 해제하시겠습니까?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"기기 카메라를 차단 해제하시겠습니까?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"기기 카메라 및 마이크를 차단 해제하시겠습니까?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"마이크를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"카메라에 액세스할 수 있는 모든 앱과 서비스에 대해 액세스가 차단 해제됩니다."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"카메라 또는 마이크를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"기기"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"위로 스와이프하여 앱 전환"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"앱을 빠르게 전환하려면 오른쪽으로 드래그"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"이더넷"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"알람"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"준비됨"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"결제 설정"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"잠금 해제하여 사용"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"카드를 가져오는 중에 문제가 발생했습니다. 나중에 다시 시도해 보세요."</string>
<string name="status_bar_work" msgid="5238641949837091056">"직장 프로필"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"비행기 모드"</string>
<string name="add_tile" msgid="6239678623873086686">"타일 추가"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>상태:</b> 무음으로 낮춤"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>상태:</b> 순위 높임"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>상태:</b> 순위 낮춤"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"우선순위 모드가 켜져 있어도 항상 알림 맨 위에 표시됩니다"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"우선순위 대화"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"설정으로 이동하여 시스템 탐색을 업데이트하세요."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"대화가 우선순위 대화로 설정됨"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"우선순위 대화"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"우선순위 대화는 목록 맨 위에 표시되며 우선순위 모드가 켜져 있을 때는 항상 표시됩니다."</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"프로필 사진이 잠금 화면에 표시됩니다."</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"홈 화면에서 풍선 모양의 대화창을 쉽게 찾을 수 있습니다."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"방해 금지 모드 무시"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"확인"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"설정"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"왼쪽 상단으로 이동"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"오른쪽 상단으로 이동"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"왼쪽 하단으로 이동"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"오른쪽 하단으로 이동"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"가장자리로 옮겨서 숨기기"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"가장자리 바깥으로 옮겨서 표시"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"연결된 기기의 컨트롤을 추가하세요."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"기기 컨트롤 설정"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> 이내"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> 이상 경과"</string>
<string name="birthday_status" msgid="2596961629465396761">"생일"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"오늘은 <xliff:g id="NAME">%1$s</xliff:g>님의 생일입니다."</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"다가오는 생일"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"곧 <xliff:g id="NAME">%1$s</xliff:g>님의 생일입니다."</string>
<string name="anniversary_status" msgid="1790034157507590838">"기념일"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"오늘은 <xliff:g id="NAME">%1$s</xliff:g>님의 기념일입니다."</string>
<string name="location_status" msgid="1294990572202541812">"위치 공유 중"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g>님이 위치를 공유하고 있습니다."</string>
<string name="new_story_status" msgid="9012195158584846525">"새 스토리"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>님이 새로운 스토리를 공유했습니다."</string>
<string name="video_status" msgid="4548544654316843225">"시청 중"</string>
<string name="audio_status" msgid="4237055636967709208">"듣는 중"</string>
<string name="game_status" msgid="1340694320630973259">"플레이 중"</string>
<string name="empty_user_name" msgid="3389155775773578300">"친구"</string>
<string name="empty_status" msgid="5938893404951307749">"오늘 밤에 채팅"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"곧 콘텐츠가 표시됩니다."</string>
<string name="missed_call" msgid="4228016077700161689">"부재중 전화"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"최근 메시지, 부재중 전화, 상태 업데이트 보기"</string>
<string name="people_tile_title" msgid="6589377493334871272">"대화"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>님이 메시지를 보냈습니다."</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>님이 이미지를 보냈습니다."</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"배터리 수준을 읽는 중에 문제가 발생함"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"탭하여 자세한 정보를 확인하세요."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"설정된 알람 없음"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 6aacfa0..2c2a8ae 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Көбүрөөк тартуу"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотту четке кагуу"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотту алдын ала көрүү"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Жогорку чеги"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Төмөнкү чеги"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Киргизүү ыкмасы"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Жайгашкан жер"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Жайгашытрууну өчүрүү"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Камераны бөгөттөө"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Микрофондун үнүн басуу"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Камераны колдонуу мүмкүнчүлүгү"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофонду колдонуу мүмкүнчүлүгү"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Жеткиликтүү"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Бөгөттөлдү"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медиа түзмөгү"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Кырсыктаганда гана чалуу"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Экранды жаздыруу"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Баштадык"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Токтотуу"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Улантуу үчүн <b><xliff:g id="APP">%s</xliff:g></b> колдонмосуна түзмөгүңүздүн микрофонун пайдаланууга уруксат беришиңиз керек."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Улантуу үчүн <b><xliff:g id="APP">%s</xliff:g></b> колдонмосуна түзмөгүңүздүн камерасын пайдаланууга уруксат беришиңиз керек."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Түзмөктүн микрофонунун кулпусу ачысынбы?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Түзмөктүн камерасынын кулпусу ачылсынбы?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Түзмөктүн камерасы менен микрофону бөгөттөн чыгарылсынбы?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ушуну менен микрофонуңузду колдонууга уруксаты бар бардык колдонмолор менен кызматтар бөгөттөн чыгарылат."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ушуну менен камераңызды колдонууга уруксаты бар бардык колдонмолор менен кызматтар бөгөттөн чыгарылат."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ушуну менен камераңызды же микрофонуңузду колдонууга уруксаты бар бардык колдонмолор менен кызматтар бөгөттөн чыгарылат."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Түзмөк"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Башка колдонмого которулуу үчүн өйдө сүрүңүз"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Колдонмолорду тез которуштуруу үчүн, оңго сүйрөңүз"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Ойготкуч"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Даяр"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Төлөмдү жөндөө"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Колдонуу үчүн кулпусун ачыңыз"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Кыйытмаларды алууда ката кетти. Бир аздан кийин кайталап көрүңүз."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Жумуш профили"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Учак режими"</string>
<string name="add_tile" msgid="6239678623873086686">"Тайл кошуу"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Абалы:</b> Үнсүз абалга төмөндөдү"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Абалы:</b> Жогорулады"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Абалы:</b> Төмөндөдү"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Маанилүү жазышуулар режими күйүп турса да, ар дайым билдирмелердин үстүндө көрүнөт"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Жөндөөлөр"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Маанилүү жазышуулар"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> жазышуу функцияларын колдоого албайт"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Бул билдирмелердин тобун бул жерде конфигурациялоого болбойт"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Жазышуу маанилүү болуп коюлду"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Маанилүү жазышуулар"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Маанилүү жазышуулар режими күйүп турганда бул жазышуулар ар дайым тизменин жогору жагында болуп, аларды тез табасыз"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Профилдин сүрөттөрү кулпуланган экранда көрүнөт"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Бул жазышууларды Башкы экраныңыздагы калкып чыкма билдирмелерден каалаганда таап алсаңыз болот"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\"Тынчымды алба\" режими үзгүлтүккө учурайт"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Түшүндүм"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Жөндөөлөр"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Убактылуу жашыруу үчүн баскычты четине жылдырыңыз"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жогорку сол жакка жылдыруу"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жогорку оң жакка жылдырыңыз"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Төмөнкү сол жакка жылдыруу"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Төмөнкү оң жакка жылдырыңыз"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ичине жылдырып, көрсөтүңүз"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Сыртка жылдырып, көрсөтүңүз"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү башкаруу элементтери"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Байланышкан түзмөктөрүңүздү башкаруу элементтерин кошосуз"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Түзмөктү башкаруу элементтерин жөндөө"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> жетпеген убакыт мурда"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> ашуун мурда"</string>
<string name="birthday_status" msgid="2596961629465396761">"Туулган күн"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> бүгүн туулган күнүн белгилеп жатат"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Алдыдагы туулган күн"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Жакында <xliff:g id="NAME">%1$s</xliff:g> туулган күнүн белгилейт"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Маараке"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> бүгүн мааракесин белгилеп жатат"</string>
<string name="location_status" msgid="1294990572202541812">"Кайда жүргөнүмдү көрсөтүү"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> кайда жүргөнүн көрсөтүп жатат"</string>
<string name="new_story_status" msgid="9012195158584846525">"Жаңы окуя"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> жаңы окуяны бөлүштү"</string>
<string name="video_status" msgid="4548544654316843225">"Көрүүдө"</string>
<string name="audio_status" msgid="4237055636967709208">"Угуп жатат"</string>
<string name="game_status" msgid="1340694320630973259">"Ойнотулууда"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Достор"</string>
<string name="empty_status" msgid="5938893404951307749">"Келиңиз, баарлашалы!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Мазмун бир аздан кийин көрүнөт"</string>
<string name="missed_call" msgid="4228016077700161689">"Жооп берилбеген чалуу"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Акыркы билдирүүлөрдү, жооп берилбеген чалууларды жана статус жаңыртууларын көрүү"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Сүйлөшүү"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> билдирүү жөнөттү"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сүрөт жөнөттү"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батареяңыздын кубаты аныкталбай жатат"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Кеңири маалымат алуу үчүн таптап коюңуз"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ойготкуч коюлган жок"</string>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 46ec23c..ea456d8 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -20,12 +20,11 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_columns">6</integer>
-
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">2</integer>
+ <integer name="quick_settings_num_columns">4</integer>
+
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">2</integer>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 51d7b8e..007f81b 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -23,12 +23,16 @@
<dimen name="docked_divider_handle_height">16dp</dimen>
<dimen name="qs_tile_margin_top">8dp</dimen>
- <dimen name="qs_tile_margin_vertical">0dp</dimen>
+
+ <!-- The height of the qs customize header. Should be
+ (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (8dp)) -
+ (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (4dp))
+ -->
+ <dimen name="qs_customize_header_min_height">44dp</dimen>
<dimen name="battery_detail_graph_space_top">9dp</dimen>
<dimen name="battery_detail_graph_space_bottom">9dp</dimen>
- <integer name="quick_settings_num_columns">4</integer>
<dimen name="qs_detail_margin_top">0dp</dimen>
<dimen name="volume_tool_tip_right_margin">136dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index fb4ecad..6001f77 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -92,8 +92,10 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ບັນທຶກເພີ່ມເຕີມ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ປິດຮູບໜ້າຈໍ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ຕົວຢ່າງຮູບໜ້າຈໍ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ຂອບເຂດທາງເທິງ"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ຂອບເຂດທາງລຸ່ມ"</string>
+ <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"ຂອບເຂດທາງເທິງ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
+ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ຂອບເຂດທາງລຸ່ມ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
+ <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ຂອບເຂດທາງຊ້າຍ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
+ <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ຂອບເຂດທາງຂວາ <xliff:g id="PERCENT">%1$d</xliff:g> ເປີເຊັນ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ກຳລັງປະມວນຜົນການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string>
@@ -349,8 +351,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ວິທີການປ້ອນຂໍ້ມູນ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ສະຖານທີ່"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ຂໍ້ມູນສະຖານທີ່ປິດຢູ່"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ບລັອກກ້ອງຖ່າຍຮູບ"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"ປິດສຽງໄມໂຄຣໂຟນ"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"ການເຂົ້າເຖິງກ້ອງຖ່າຍຮູບ"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"ການເຂົ້າເຖິງໄມ"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ສາມາດໃຊ້ໄດ້"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ບລັອກແລ້ວ"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ອຸປະກອນສື່"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ໂທສຸກເສີນເທົ່ານັ້ນ"</string>
@@ -422,8 +426,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ການບັນທຶກໜ້າຈໍ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ເລີ່ມ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ຢຸດ"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ເພື່ອດຳເນີນການຕໍ່, <b><xliff:g id="APP">%s</xliff:g></b> ຕ້ອງການສິດເຂົ້າເຖິງໄມໂຄຣໂຟນອຸປະກອນຂອງທ່ານ."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ເພື່ອດຳເນີນການຕໍ່, <b><xliff:g id="APP">%s</xliff:g></b> ຕ້ອງການສິດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງອຸປະກອນທ່ານ."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ຍົກເລີກການບລັອກໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ຍົກເລີກການບລັອກກ້ອງຖ່າຍຮູບອຸປະກອນບໍ?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ຍົກເລີກການບລັອກກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ນີ້ຈະຍົກເລີກການບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ໄມໂຄຣໂຟນຂອງທ່ານ."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ນີ້ຈະຍົກເລີກການບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ກ້ອງຖ່າຍຮູບຂອງທ່ານ."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ນີ້ຈະຍົກເລີກການບລັອກການເຂົ້າເຖິງແອັບ ແລະ ບໍລິການທັງໝົດທີ່ອະນຸຍາດໃຫ້ໃຊ້ກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນຂອງທ່ານ."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ອຸປະກອນ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ປັດຂື້ນເພື່ອສະຫຼັບແອັບ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ລາກໄປຂວາເພື່ອສະຫຼັບແອັບດ່ວນ"</string>
@@ -657,8 +665,8 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ອີເທເນັດ"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"ໂມງປຸກ"</string>
<string name="wallet_title" msgid="5369767670735827105">"ກະເປົາ"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"ສະແດງທັງໝົດ"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"ປົດລັອກເພື່ອຈ່າຍ"</string>
+ <string name="wallet_app_button_label" msgid="7123784239111190992">"ສະແດງທັງໝົດ"</string>
+ <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"ປົດລັອກເພື່ອຈ່າຍ"</string>
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"ພ້ອມແລ້ວ"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ຕັ້ງຄ່າການຈ່າຍເງິນ"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ປົດລັອກເພື່ອໃຊ້"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 12b65a2..424eeec 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Fiksuoti daugiau"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Praleisti ekrano kopiją"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrano kopijos peržiūra"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Viršutinė riba"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Apatinė riba"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrano vaizdo įrašytuvas"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Įvesties metodas"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vietovė"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Vietovė išjungta"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokuoti Fotoaparatą"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Nutildyti mikrofoną"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Prieiga prie fotoaparato"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Prieiga prie mikrofono"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Pasiekiama"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Užblokuota"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijos įrenginys"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Tik skambučiai pagalbos numeriu"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekrano įrašas"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Pradėti"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stabdyti"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Kad būtų galima tęsti, <b><xliff:g id="APP">%s</xliff:g></b> reikalinga prieiga prie įrenginio mikrofono."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Kad būtų galima tęsti, <b><xliff:g id="APP">%s</xliff:g></b> reikalinga prieiga prie įrenginio fotoaparato."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Panaikinti įrenginio mikrofono blokavimą?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Panaikinti įrenginio fotoaparato blokavimą?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Panaikinti įrenginio fotoaparato ir mikrofono blokavimą?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti mikrofoną."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti fotoaparatą."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tai atlikus visų programų ir paslaugų prieigos blokavimas panaikinamas ir joms leidžiama naudoti fotoaparatą ar mikrofoną."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Įrenginys"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Perbraukite aukštyn, kad perjungtumėte programas"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Vilkite į dešinę, kad greitai perjungtumėte programas"</string>
@@ -663,8 +675,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Eternetas"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Signalas"</string>
<string name="wallet_title" msgid="5369767670735827105">"Piniginė"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Rodyti viską"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Atrakinti, kad būtų galima mokėti"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Paruošta"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Nustatyti mokėjimą"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Atrakinti, kad būtų galima naudoti"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e4e19d9..5c863587 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Tvert vairāk"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Nerādīt ekrānuzņēmumu"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrānuzņēmuma priekšskatījums"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Augšējā robeža"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Apakšējā robeža"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrāna ierakstītājs"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string>
@@ -350,8 +356,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Ievades metode"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Atrašanās vieta"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Atrašanās vieta izslēgta"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloķēt kameru"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Izslēgt mikrofonu"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Piekļuve kamerai"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Piekļuve mikrofonam"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Piekļuve atļauta"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Piekļuve bloķēta"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Multivides ierīce"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Tikai ārkārtas izsaukumi"</string>
@@ -424,8 +432,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekrāna ierakstīšana"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Sākt"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Apturēt"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Lai turpinātu, lietotnei <b><xliff:g id="APP">%s</xliff:g></b> nepieciešama piekļuve jūsu ierīces mikrofonam."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Lai turpinātu, lietotnei <b><xliff:g id="APP">%s</xliff:g></b> nepieciešama piekļuve jūsu ierīces kamerai."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vai vēlaties atbloķēt ierīces mikrofonu?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vai vēlaties atbloķēt ierīces kameru?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vai vēlaties atbloķēt ierīces kameru un mikrofonu?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Visas lietotnes un pakalpojumi, kas drīkst izmantot mikrofonu, varēs tam piekļūt."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Visas lietotnes un pakalpojumi, kas drīkst izmantot kameru, varēs tai piekļūt."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Visas lietotnes un pakalpojumi, kas drīkst izmantot kameru vai mikrofonu, varēs piekļūt kamerai vai mikrofonam."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Ierīce"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Velciet augšup, lai pārslēgtu lietotnes"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Lai ātri pārslēgtu lietotnes, velciet pa labi"</string>
@@ -660,8 +672,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Tīkls Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Signāls"</string>
<string name="wallet_title" msgid="5369767670735827105">"Maks"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Rādīt visu"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Lai maksātu, atbloķējiet ekrānu"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Gatavs"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Maksājuma veida iestatīšana"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lai izmantotu, atbloķējiet ekrānu"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 87246ce..25bc0e9 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Сними повеќе"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Отфрлете ја сликата од екранот"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед на слика од екранот"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Горна граница"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Долна граница"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач на екран"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Се обработува снимка од екран"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string>
@@ -300,7 +306,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1490779000057752281">"Податоците 4G се паузирани"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="2286843518689837719">"Мобилниот интернет е паузиран"</string>
<string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"Податоците се паузирани"</string>
- <string name="data_usage_disabled_dialog" msgid="7933201635215099780">"Го достигнавте ограничувањето за мобилен сообраќај што сте го поставиле. Веќе не користите мобилен интернет.\n\nДоколку продолжите, ќе ви биде наплатено за потрошениот сообраќај."</string>
+ <string name="data_usage_disabled_dialog" msgid="7933201635215099780">"Го достигнавте ограничувањето за мобилен интернет што сте го поставиле. Веќе не користите мобилен интернет.\n\nДоколку продолжите, ќе ви биде наплатено за потрошениот интернет."</string>
<string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"Продолжи"</string>
<string name="gps_notification_searching_text" msgid="231304732649348313">"Се пребарува за GPS"</string>
<string name="gps_notification_found_text" msgid="3145873880174658526">"Локацијата е поставена со GPS"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод на внес"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Исклучи локација"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Блокирај камера"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Исклучи звук на микрофонот"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Пристап до камерата"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Пристап до микрофонот"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Достапен"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Блокиран"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медиумски уред"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Само итни повици"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Снимање екран"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Започни"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Сопри"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"За да продолжи, на <b><xliff:g id="APP">%s</xliff:g></b> ѝ е потребен пристап до микрофонот на уредот."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"За да продолжи, на <b><xliff:g id="APP">%s</xliff:g></b> ѝ е потребен пристап до камерата на уредот."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се одблокира пристапот до микрофонот на уредот?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се одблокира пристапот до камерата на уредот?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се одблокира пристапот до камерата и микрофонот на уредот?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на микрофонот."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на камерата."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ова ќе го одблокира пристапот за сите апликации и услуги на кои им е дозволено користење на камерата или микрофонот."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Уред"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Повлечете нагоре за да се префрлите од една на друга апликација"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Повлечете надесно за брзо префрлање меѓу апликациите"</string>
@@ -497,7 +509,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Ја намалува изведбата и податоците во заднина"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Исклучете го штедачот на батерија"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе има пристап до сите податоци што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува податоци како лозинки, детали за плаќање, фотографии, пораки, аудио што го пуштате итн."</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата што ја обезбедува функцијава ќе има пристап до сите податоци што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува информации како лозинки, детали за плаќање, фотографии, пораки, аудио што го пуштате итн."</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата што ја обезбедува функцијава ќе има пристап до сите податоци што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува податоци како лозинки, детали за плаќање, фотографии, пораки, аудио што го пуштате итн."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Да почне снимање или емитување?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Да почне снимање или емитување со <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"Не покажувај повторно"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Етернет"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Аларм"</string>
<string name="wallet_title" msgid="5369767670735827105">"Паричник"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Прикажи ги сите"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Отклучете за да платите"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Подготвено"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Поставете плаќање"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отклучете за да користите"</string>
@@ -968,7 +982,7 @@
<string name="qs_dnd_keep" msgid="3829697305432866434">"Задржи"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"Замени"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Апликациите се извршуваат во заднина"</string>
- <string name="running_foreground_services_msg" msgid="3009459259222695385">"Допрете за детали за батеријата и потрошениот сообраќај"</string>
+ <string name="running_foreground_services_msg" msgid="3009459259222695385">"Допрете за детали за батеријата и потрошениот интернет"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Да се исклучи мобилниот интернет?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Нема да имате пристап до податоците или интернетот преку <xliff:g id="CARRIER">%s</xliff:g>. Интернетот ќе биде достапен само преку Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"вашиот оператор"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 955f144..bf38d28 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"കൂടുതൽ ക്യാപ്ചർ ചെയ്യുക"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"സ്ക്രീൻഷോട്ട് ഡിസ്മിസ് ചെയ്യുക"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"സ്ക്രീൻഷോട്ട് പ്രിവ്യു"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"മുകളിലുള്ള അതിർത്തി"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ചുവടെയുള്ള അതിർത്തി"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"സ്ക്രീൻ റെക്കോർഡർ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ടൈപ്പുചെയ്യൽ രീതി"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ലൊക്കേഷൻ"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ലൊക്കേഷൻ ഓഫാണ്"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ക്യാമറ ബ്ലോക്ക് ചെയ്യുക"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"മൈക്രോഫോൺ മ്യൂട്ട് ചെയ്യുക"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"ക്യാമറ ആക്സസ്"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"മൈക്ക് ആക്സസ്"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ലഭ്യമാണ്"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"മീഡിയ ഉപകരണം"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"അടിയന്തിര കോളുകൾ മാത്രം"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"സ്ക്രീൻ റെക്കോർഡ്"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ആരംഭിക്കുക"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"നിര്ത്തുക"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"തുടരാൻ, <b><xliff:g id="APP">%s</xliff:g></b> ആപ്പിന് നിങ്ങളുടെ ഉപകരണത്തിന്റെ മൈക്രോഫോണിലേക്ക് ആക്സസ് നൽകേണ്ടതുണ്ട്."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"തുടരാൻ, <b><xliff:g id="APP">%s</xliff:g></b> ആപ്പിന് നിങ്ങളുടെ ഉപകരണത്തിന്റെ ക്യാമറയിലേക്ക് ആക്സസ് നൽകേണ്ടതുണ്ട്."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ഉപകരണ മൈക്രോഫോൺ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ഉപകരണ ക്യാമറ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ഉപകരണ ക്യാമറയോ മൈക്രോഫോണോ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"നിങ്ങളുടെ മൈക്രോഫോൺ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"നിങ്ങളുടെ ക്യാമറ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"നിങ്ങളുടെ ക്യാമറയോ മൈക്രോഫോണോ ഉപയോഗിക്കാൻ അനുവദിച്ചിരിക്കുന്ന എല്ലാ ആപ്പുകൾക്കും സേവനങ്ങൾക്കുമുള്ള ആക്സസ് ഇത് അൺബ്ലോക്ക് ചെയ്യുന്നു."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ഉപകരണം"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ആപ്പുകൾ മാറാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ആപ്പുകൾ പെട്ടെന്ന് മാറാൻ വലത്തോട്ട് വലിച്ചിടുക"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ഇതർനെറ്റ്"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"അലാറം"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"തയ്യാർ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"പേയ്മെന്റ് സജ്ജീകരിക്കുക"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"നിങ്ങളുടെ കാർഡുകൾ ലഭ്യമാക്കുന്നതിൽ ഒരു പ്രശ്നമുണ്ടായി, പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string>
<string name="status_bar_work" msgid="5238641949837091056">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ഫ്ലൈറ്റ് മോഡ്"</string>
<string name="add_tile" msgid="6239678623873086686">"ടൈൽ ചേർക്കുക"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>നില:</b> നിശബ്ദമാക്കി തരം താഴ്ത്തി"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>നില:</b> ഉയർന്ന റാങ്കിംഗ് നൽകി"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>നില:</b> താഴ്ന്ന റാങ്കിംഗ് നൽകി"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"മുൻഗണനാ മോഡ് ഓണാണെങ്കിൽ പോലും എപ്പോഴും അറിയിപ്പുകളുടെ മുകളിൽ കാണിക്കും"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"മുൻഗണനാ സംഭാഷണങ്ങൾ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> സംഭാഷണ സവിശേഷതകളെ പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്ഫിഗര് ചെയ്യാൻ കഴിയില്ല"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്റ്റം നാവിഗേഷൻ അപ്ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്റ്റാൻഡ്ബൈ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"സംഭാഷണം മുൻഗണനയുള്ളതായി സജ്ജീകരിച്ചു"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"മുൻഗണനാ സംഭാഷണങ്ങൾ"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ഈ സംഭാഷണങ്ങൾ ലിസ്റ്റിന്റെ മുകളിൽ കാണിക്കും, മുൻഗണനാ മോഡ് ഓണാണെങ്കിൽ, എപ്പോഴും നിങ്ങളിലേക്ക് എത്താൻ അവയ്ക്ക് കഴിയും"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"പ്രൊഫെെൽ ചിത്രങ്ങൾ ലോക്ക് സ്ക്രീനിൽ കാണിക്കും"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"ഹോം സ്ക്രീനിലെ ബബിളുകളിൽ ഈ സംഭാഷണങ്ങൾ നിങ്ങൾക്ക് എളുപ്പത്തിൽ കണ്ടെത്താനാകും"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ശല്യപ്പെടുത്തരുത്\' തടസ്സപ്പെടുത്തുക"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"മനസ്സിലായി"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ക്രമീകരണം"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"തൽക്കാലം മറയ്ക്കുന്നതിന് ബട്ടൺ അരുകിലേക്ക് നീക്കുക"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"മുകളിൽ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"എഡ്ജിലേക്ക് നീക്കി മറയ്ക്കുക"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"എഡ്ജിൽ നിന്ന് നീക്കി കാണിക്കൂ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ഉപകരണ നിയന്ത്രണങ്ങൾ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"കണക്റ്റ് ചെയ്ത ഉപകരണങ്ങൾക്ക് നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ഉപകരണ നിയന്ത്രണങ്ങൾ സജ്ജീകരിക്കുക"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> എന്നതിൽ കുറവ്"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> മുമ്പ്"</string>
<string name="birthday_status" msgid="2596961629465396761">"ജന്മദിനം"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> എന്ന വ്യക്തിയുടെ ജന്മദിനമാണിന്ന്"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ഉടൻ വരുന്ന ജന്മദിനം"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> എന്ന വ്യക്തിയുടെ ജന്മദിനം ഉടൻ വരുന്നുണ്ട്"</string>
<string name="anniversary_status" msgid="1790034157507590838">"വാര്ഷികം"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> എന്ന വ്യക്തിയുടെ വാർഷികമാണിന്ന്"</string>
<string name="location_status" msgid="1294990572202541812">"ലൊക്കേഷൻ പങ്കിടുന്നു"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g>, ലൊക്കേഷൻ പങ്കിടുന്നു"</string>
<string name="new_story_status" msgid="9012195158584846525">"പുതിയ വാർത്ത"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>, പുതിയൊരു സ്റ്റോറി പങ്കിട്ടു"</string>
<string name="video_status" msgid="4548544654316843225">"കാണുന്നു"</string>
<string name="audio_status" msgid="4237055636967709208">"കേൾക്കുന്നു"</string>
<string name="game_status" msgid="1340694320630973259">"കളിക്കുന്നു"</string>
<string name="empty_user_name" msgid="3389155775773578300">"സുഹൃത്തുക്കൾ"</string>
<string name="empty_status" msgid="5938893404951307749">"ഇന്നുരാത്രി ചാറ്റുചെയ്യാം!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"ഉള്ളടക്കം ഉടൻ ദൃശ്യമാകും"</string>
<string name="missed_call" msgid="4228016077700161689">"മിസ്ഡ് കോൾ"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"അടുത്തിടെയുള്ള സന്ദേശങ്ങൾ, മിസ്ഡ് കോളുകൾ, സ്റ്റാറ്റസ് അപ്ഡേറ്റുകൾ എന്നിവ കാണുക"</string>
<string name="people_tile_title" msgid="6589377493334871272">"സംഭാഷണം"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>, ഒരു സന്ദേശം അയച്ചു"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>, ഒരു ചിത്രം അയച്ചു"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"നിങ്ങളുടെ ബാറ്ററി മീറ്റർ വായിക്കുന്നതിൽ പ്രശ്നമുണ്ട്"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"കൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"അലാറം സജ്ജീകരിച്ചിട്ടില്ല"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8cdd8d4..9043a7f 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Ихийг багтаасан зураг авах"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Дэлгэцийн агшныг хаах"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Дэлгэцийн агшныг урьдчилан үзэх"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Дээд талын хязгаар"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Доод талын хязгаар"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Дэлгэцийн үйлдэл бичигч"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Оруулах арга"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Байршил"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Байршил идэвхгүй"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Камерыг блоклох"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Микрофоны дууг хаах"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Камерын хандалт"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофоны хандалт"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Боломжтой"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Блоклосон"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медиа төхөөрөмж"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Зөвхөн яаралтай дуудлага"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Дэлгэцийн бичлэг хийх"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Эхлүүлэх"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зогсоох"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Үргэлжлүүлэхийн тулд <b><xliff:g id="APP">%s</xliff:g></b> таны төхөөрөмжийн микрофонд хандах шаардлагатай."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Үргэлжлүүлэхийн тулд <b><xliff:g id="APP">%s</xliff:g></b> таны төхөөрөмжийн камерт хандах шаардлагатай."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Төхөөрөмжийн микрофоныг блокоос гаргах уу?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Төхөөрөмжийн камерыг блокоос гаргах уу?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Төхөөрөмжийн камер болон микрофоныг блокоос гаргах уу?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Энэ нь таны микрофоныг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Энэ нь таны камерыг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Энэ нь таны камер эсвэл микрофоныг ашиглах зөвшөөрөлтэй бүх апп болон үйлчилгээний хандалтыг блокоос гаргана."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Төхөөрөмж"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Апп сэлгэхийн тулд дээш шударна уу"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Аппуудыг хурдан сэлгэхийн тулд баруун тийш чирнэ үү"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Этернет"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Сэрүүлэг"</string>
<string name="wallet_title" msgid="5369767670735827105">"Түрийвч"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Бэлэн"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Төлбөр тохируулах"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ашиглахын тулд түгжээг тайлах"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Таны картыг авахад асуудал гарлаа. Дараа дахин оролдоно уу"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Ажлын профайл"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Нислэгийн горим"</string>
<string name="add_tile" msgid="6239678623873086686">"Вебсайтын цонх нэмэх"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Төлөв:</b> Чимээгүй болгож зэрэглэлийг нь бууруулсан"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Төлөв:</b> Дээгүүр зэрэглэл хийсэн"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Төлөв:</b> Доогуур зэрэглэл хийсэн"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Чухал горим асаалттай байсан ч таны мэдэгдлийн дээр үргэлж харуулдаг"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Тохиргоо"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Чухал харилцан яриа"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Энэ бүлэг мэдэгдлийг энд тохируулах боломжгүй байна"</string>
@@ -839,7 +845,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Хөгжим"</string>
<string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string>
- <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Хуанли"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календарь"</string>
<string name="tuner_full_zen_title" msgid="5120366354224404511">"Түвшний хяналттай харуулах"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"Бүү саад бол"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Дууны түвшний товчлуурын товчлол"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Системийн навигацыг шинэчлэхийн тулд Тохиргоо руу очно уу"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Харилцан яриаг чухал гэж тохируулсан"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Чухал харилцан яриа"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Эдгээр харилцан яриаг Чухал горим асаалттай үед таны жагсаалтын дээр харуулах бөгөөд танд үргэлж харуулах боломжтой"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Профайл зургийг түгжигдсэн дэлгэц дээр харуулдаг"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Та бөмбөлгүүд дэх эдгээр харилцан яриаг Үндсэн нүүрээсээ хялбархан олох боломжтой"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Бүү саад бол онцлогийг үл хэрэгсэн тасалдуулна"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ойлголоо"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Тохиргоо"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Үүнийг түр нуухын тулд товчлуурыг зах руу зөөнө үү"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Зүүн дээш зөөх"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Баруун дээш зөөх"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Зүүн доош зөөх"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Баруун доош зөөх"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ирмэг рүү зөөж, нуух"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ирмэгээс гаргаж, харуулах"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Холбогдсон төхөөрөмжүүд дээрээ хяналт нэмэх"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Төхөөрөмжийн хяналтыг тохируулах"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>-с бага хугацааны өмнө"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>-с дээш хугацааны өмнө"</string>
<string name="birthday_status" msgid="2596961629465396761">"Төрсөн өдөр"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Өнөөдөр <xliff:g id="NAME">%1$s</xliff:g>-н төрсөн өдөр болж байна"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Удахгүй болох төрсөн өдөр"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Удахгүй <xliff:g id="NAME">%1$s</xliff:g>-н төрсөн өдөр болно"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Тэмдэглэлт ой"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Өнөөдөр <xliff:g id="NAME">%1$s</xliff:g>-н ой тохиож байна"</string>
<string name="location_status" msgid="1294990572202541812">"Байршил хуваалцаж байна"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> байршил хуваалцаж байна"</string>
<string name="new_story_status" msgid="9012195158584846525">"Шинэ стори"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> шинэ стори хуваалцсан"</string>
<string name="video_status" msgid="4548544654316843225">"Үзэж байна"</string>
<string name="audio_status" msgid="4237055636967709208">"Сонсож байна"</string>
<string name="game_status" msgid="1340694320630973259">"Тоглож байна"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Найзууд"</string>
<string name="empty_status" msgid="5938893404951307749">"Өнөө орой чаталъя!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Контент удахгүй харагдана"</string>
<string name="missed_call" msgid="4228016077700161689">"Аваагүй дуудлага"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Саяхны мессеж, аваагүй дуудлага болон төлөвийн шинэчлэлтийг харах"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Харилцан яриа"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> мессеж илгээсэн"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> зураг илгээсэн"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Таны батарей хэмжигчийг уншихад асуудал гарлаа"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нэмэлт мэдээлэл авахын тулд товшино уу"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Сэрүүлэг тавиагүй"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 77e2694..4a1e331 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"आणखी गोष्टी कॅप्चर करा"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट डिसमिस करा"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉटचे पूर्वावलोकन"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"सर्वात वरची सीमा"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"तळाची सीमा"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रेकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"इनपुट पद्धत"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"स्थान बंद"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"कॅमेरा ब्लॉक करा"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"मायक्रोफोन म्यूट करा"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"मीडिया डिव्हाइस"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"फक्त आणीबाणीचे कॉल"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्क्रीन रेकॉर्ड"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरू"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"थांबा"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"पुढे सुरू ठेवण्यासाठी, <b><xliff:g id="APP">%s</xliff:g></b> ला तुमच्या डिव्हाइसचा मायक्रोफोन अॅक्सेस करण्याची आवश्यकता आहे."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"पुढे सुरू ठेवण्यासाठी, <b><xliff:g id="APP">%s</xliff:g></b> ला तुमच्या डिव्हाइसचा कॅमेरा अॅक्सेस करण्याची आवश्यकता आहे."</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"डिव्हाइस"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"अॅप्स स्विच करण्यासाठी वर स्वाइप करा"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"अॅप्स वर झटपट स्विच करण्यासाठी उजवीकडे ड्रॅग करा"</string>
@@ -497,7 +519,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"कामगिरी आणि पार्श्वभूमीवरील डेटा कमी करते"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"बॅटरी सेव्हर बंद करा"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"तुमच्या स्क्रीनवर दृश्यमान असलेल्या किंवा रेकॉर्ड किंवा कास्ट करताना तुमच्या डिव्हाइसमधून प्ले केलेल्या सर्व माहितीचा अॅक्सेस <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ला असेल. यामध्ये पासवर्ड, पेमेंट तपशील, फोटो, मेसेज आणि तुम्ही प्ले केलेला ऑडिओ यासारख्या माहितीचा समावेश असतो."</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"हे कार्य पुरवठा करणाऱ्या सेवेस तुमच्या स्क्रीनवर दृश्यमान असलेल्या किंवा रेकॉर्ड किंवा कास्ट करताना तुमच्या डिव्हाइसमधून प्ले केलेल्या सर्व माहितीचा अॅक्सेस असेल. यामध्ये पासवर्ड, पेमेंट तपशील, फोटो, मेसेज आणि तुम्ही प्ले केलेला ऑडिओ यासारख्या माहितीचा समावेश असतो."</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"हे कार्य पुरवणाऱ्या सेवेस तुमच्या स्क्रीनवर दृश्यमान असलेल्या किंवा रेकॉर्ड किंवा कास्ट करताना तुमच्या डिव्हाइसमधून प्ले केलेल्या सर्व माहितीचा अॅक्सेस असेल. यामध्ये पासवर्ड, पेमेंट तपशील, फोटो, मेसेज आणि तुम्ही प्ले केलेला ऑडिओ यासारख्या माहितीचा समावेश असतो."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकॉर्ड करणे किंवा कास्ट करणे सुरू करायचे का ?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ने रेकॉर्ड करणे किंवा कास्ट करणे सुरू करायचे का?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"पुन्हा दर्शवू नका"</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"इथरनेट"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"अलार्म"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"तयार आहे"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"पेमेंट सेट करा"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"वापरण्यासाठी अनलॉक करा"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"तुमची कार्ड मिळवताना समस्या आली, कृपया नंतर पुन्हा प्रयत्न करा"</string>
<string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string>
<string name="add_tile" msgid="6239678623873086686">"टाइल जोडा"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>स्थिती</b> ला सायलंट म्हणून डीमोट केले गेले"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>स्थिती</b> ला थोडे जास्त म्हणून रँक केले गेले"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>स्थिती</b> ला थोडी कमी म्हणून रँक केले गेले"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"प्राधान्य मोड सुरू असतानादेखील, नेहमी तुमच्या सूचनांच्या वरती दाखवले जाते"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग्ज"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"प्राधान्य दिलेली संभाषणे"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"या सूचनांचा संच येथे कॉंफिगर केला जाऊ शकत नाही"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"संभाषणाला प्राधान्य म्हणून सेट केले आहे"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"प्राधान्य दिलेली संभाषणे"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ही संभाषणे तुमच्या सूचीच्या सर्वात वरती दाखवली जातात आणि प्राधान्य मोड सुरू असताना तुम्हाला नेहमी कळू शकते"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"प्रोफाइल फोटो लॉक स्क्रीनवर दाखवले जातात"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"तुम्हाला तुमच्या होम स्क्रीन वरील बबलमध्ये ही संभाषणे सहज आढळतील"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"व्यत्यय आणू नका मध्ये अडथळा आणतील"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"समजले"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"सेटिंग्ज"</string>
@@ -1040,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटण तात्पुरते लपवण्यासाठी ते कोपर्यामध्ये हलवा"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"वर डावीकडे हलवा"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"वर उजवीकडे हलवा"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"तळाशी डावीकडे हलवा"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"तळाशी उजवीकडे हलवा"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एजवर हलवा आणि लपवा"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एजवर हलवा आणि दाखवा"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"डिव्हाइस नियंत्रणे"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"तुमच्या कनेक्ट केलेल्या डिव्हाइससाठी नियंत्रणे जोडा"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"डिव्हाइस नियंत्रणे सेट करा"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> पेक्षा कमी"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> पेक्षा आधी"</string>
<string name="birthday_status" msgid="2596961629465396761">"वाढदिवस"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"आज <xliff:g id="NAME">%1$s</xliff:g> यांचा वाढदिवस आहे"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"वाढदिवस लवकरच आहे"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> यांचा वाढदिवस लवकरच येत आहे"</string>
<string name="anniversary_status" msgid="1790034157507590838">"वर्धापन दिन"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"आज <xliff:g id="NAME">%1$s</xliff:g> यांची अॅनिव्हर्सरी आहे"</string>
<string name="location_status" msgid="1294990572202541812">"स्थान शेअर करत आहे"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> स्थान शेअर करत आहे"</string>
<string name="new_story_status" msgid="9012195158584846525">"नवीन स्टोरी"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> यांनी नवीन स्टोरी शेअर केली"</string>
<string name="video_status" msgid="4548544654316843225">"पाहत आहे"</string>
<string name="audio_status" msgid="4237055636967709208">"ऐकत आहे"</string>
<string name="game_status" msgid="1340694320630973259">"प्ले करत आहे"</string>
<string name="empty_user_name" msgid="3389155775773578300">"मित्रमैत्रिणी"</string>
<string name="empty_status" msgid="5938893404951307749">"चला, आज रात्री चॅट करूया!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"आशय लवकरच दाखवला जाईल"</string>
<string name="missed_call" msgid="4228016077700161689">"मिस्ड कॉल"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"अलीकडील मेसेज, मिस्ड कॉल आणि स्टेटस अपडेट पाहा"</string>
<string name="people_tile_title" msgid="6589377493334871272">"संभाषण"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> यांनी मेसेज पाठवला"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> यांनी इमेज पाठवली"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"तुमचे बॅटरी मीटर वाचताना समस्या आली"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"अधिक माहितीसाठी टॅप करा"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"अलार्म सेट केला नाही"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6e90234..1b61ce9 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Tangkap lebih banyak"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ketepikan tangkapan skrin"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pratonton tangkapan skrin"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Sempadan atas"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Sempadan bawah"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Perakam Skrin"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses rakaman skrin"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pemberitahuan breterusan untuk sesi rakaman skrin"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Kaedah Input"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokasi Dimatikan"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Sekat Kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Redamkan Mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Akses kamera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Akses mikrofon"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tersedia"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Disekat"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Peranti media"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Panggilan Kecemasan Sahaja"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rakam Skrin"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mula"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Untuk meneruskan proses, <b><xliff:g id="APP">%s</xliff:g></b> memerlukan akses kepada mikrofon peranti anda."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Untuk meneruskan proses, <b><xliff:g id="APP">%s</xliff:g></b> memerlukan akses kepada kamera peranti anda."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Nyahsekat mikrofon peranti?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Nyahsekat kamera peranti?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Nyahsekat kamera dan mikrofon peranti?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan mikrofon anda."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera anda."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Tindakan ini menyahsekat akses bagi semua apl dan perkhidmatan yang dibenarkan untuk menggunakan kamera atau mikrofon anda."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Peranti"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Leret ke atas untuk menukar apl"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Seret ke kanan untuk beralih apl dengan pantas"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Penggera"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Tunjukkan semua"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Buka kunci untuk membayar"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Sedia"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Sediakan pembayaran"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 091a384..e5282b9 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -45,7 +45,7 @@
<string name="status_bar_settings_notifications" msgid="5285316949980621438">"အကြောင်းကြားချက်များ"</string>
<string name="bluetooth_tethered" msgid="4171071193052799041">"ဘလူးတုသ်မှတဆင့်ပြန်လည်ချိတ်ဆက်ခြင်း"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"ထည့်သွင်းနည်းများ သတ်မှတ်ခြင်း"</string>
- <string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"ခလုတ်ပါဝင်သော ကီးဘုတ်"</string>
+ <string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"စက်၏ ကီးဘုတ်"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> အား ဝင်သုံးရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ခွင့်ပြုပါသလား။"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> အား <xliff:g id="USB_DEVICE">%2$s</xliff:g> ကို သုံးခွင့်ပြုမလား။\nဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string>
<string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> အား ဝင်သုံးရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ခွင့်ပြုပါသလား။"</string>
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"နောက်ထပ် ရိုက်ကူးရန်"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ဖန်သားပြင်ဓာတ်ပုံကို ပယ်သည်"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ဖန်သားပြင်ဓာတ်ပုံ အစမ်းကြည့်ရှုခြင်း"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ထိပ်ပိုင်းအနားသတ်"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"အောက်ခြေအနားသတ်"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ဖန်သားပြင် ရိုက်ကူးမှု"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ဖန်သားပြင်ရိုက်ကူးနေသည်"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ထည့်သွင်းရန်နည်းလမ်း"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"တည်နေရာ"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"တည်နေရာပြမှု မရှိ"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ကင်မရာကို ပိတ်ထားရန်"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"မိုက်ခရိုဖုန်းကို အသံတိတ်ရန်"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"ကင်မရာသုံးခွင့်"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"မိုက်သုံးခွင့်"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ရနိုင်သည်"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ပိတ်ထားသည်"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"မီဒီယာ စက်ပစ္စည်း"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"အရေးပေါ်ခေါ်ဆိုမှုများသာ"</string>
@@ -386,7 +394,7 @@
<string name="quick_settings_connected" msgid="3873605509184830379">"ချိတ်ဆက်ထား"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"ချိတ်ဆက်ပြီးပါပြီ၊ ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="2381969772953268809">"ဆက်သွယ်နေ..."</string>
- <string name="quick_settings_tethering_label" msgid="5257299852322475780">"တွဲချီပေးခြင်း"</string>
+ <string name="quick_settings_tethering_label" msgid="5257299852322475780">"မိုဘိုင်းသုံးတွဲချိတ်ခြင်း"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"ဟော့စပေါ့"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"ဖွင့်နေသည်…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"\'ဒေတာချွေတာမှု\' ဖွင့်ထားသည်"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ဖန်သားပြင် မှတ်တမ်းတင်ရန်"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"စတင်ရန်"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ရပ်ရန်"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ဆက်လက်လုပ်ဆောင်ရန် <b><xliff:g id="APP">%s</xliff:g></b> က သင့်စက်၏ မိုက်ခရိုဖုန်းကို အသုံးပြုခွင့်ရရန် လိုအပ်သည်။"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ဆက်လက်လုပ်ဆောင်ရန် <b><xliff:g id="APP">%s</xliff:g></b> က သင့်စက်၏ ကင်မရာကို အသုံးပြုခွင့်ရရန် လိုအပ်သည်။"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"စက်၏မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"စက်၏ကင်မရာကို ပြန်ဖွင့်မလား။"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"စက်၏ကင်မရာနှင့် မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"၎င်းက သင့်မိုက်ခရိုဖုန်းသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"၎င်းက သင့်ကင်မရာသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"၎င်းက သင့်ကင်မရာ (သို့) မိုက်ခရိုဖုန်းသုံးရန် ခွင့်ပြုထားသော အက်ပ်နှင့် ဝန်ဆောင်မှုအားလုံးအတွက် သုံးခွင့်ကို ပြန်ဖွင့်ပေးသည်။"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"စက်"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"အက်ပ်များကို ဖွင့်ရန် အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"အက်ပ်များကို ပြောင်းရန် ညာဘက်သို့ ဖိဆွဲပါ"</string>
@@ -497,7 +509,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"လုပ်ကိုင်မှုကို လျှော့ချလျက် နောက်ခံ ဒေတာကို ကန့်သတ်သည်"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ဘက်ထရီ အားထိန်းကို ပိတ်ရန်"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်ဖန်သားပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်နိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ဤလုပ်ရပ်အတွက် ဝန်ဆောင်မှုသည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်ဖန်သားပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပြီး သင့်စက်မှ ဖွင့်နိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ဤဝန်ဆောင်မှုသည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ်အတွင်း သင့်ဖန်သားပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်အားလုံးကို ကြည့်နိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> နှင့် ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"နောက်ထပ် မပြပါနှင့်"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"အီသာနက်"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"နှိုးစက်"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"အဆင်သင့်"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ငွေပေးချေမှု သတ်မှတ်ရန်"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"သုံးရန် လော့ခ်ဖွင့်ပါ"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"သင်၏ကတ်များ ရယူရာတွင် ပြဿနာရှိနေသည်၊ နောက်မှ ထပ်စမ်းကြည့်ပါ"</string>
<string name="status_bar_work" msgid="5238641949837091056">"အလုပ် ပရိုဖိုင်"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"လေယာဉ်ပျံမုဒ်"</string>
<string name="add_tile" msgid="6239678623873086686">"လေးထောင့်ကွက် ထည့်ရန်"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>အခြေအနေ-</b> အသံတိတ်ခြင်းသို့ ပြန်ချိန်ညှိထားသည်"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>အခြေအနေ-</b> အဆင့်တိုးထားသည်"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>အခြေအနေ-</b> အဆင့်လျှော့ထားသည်"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"‘ဦးစားပေးမုဒ်’ ကို ဖွင့်ထားသည့်အခါတွင်ပင် သင့်အကြောင်းကြားချက်များ၏ ထိပ်ဆုံးတွင် အမြဲပြသည်"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ဆက်တင်များ"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"ဦးစားပေး စကားဝိုင်းများ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ဤအကြောင်းကြားချက်အုပ်စုကို ဤနေရာတွင် စီစဉ်သတ်မှတ်၍ မရပါ"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"အသင့်အနေအထား"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"စကားဝိုင်းကို ဦးစားပေးအဖြစ် သတ်မှတ်ထားသည်"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"ဦးစားပေး စကားဝိုင်းများ"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ဤစကားဝိုင်းများကို သင့်စာရင်း၏ထိပ်ဆုံးတွင် ပြပေးပြီး ‘ဦးစားပေးမုဒ်’ ကို ဖွင့်ထားသောအခါ သင့်ထံသို့ အမြဲရောက်ရှိနိုင်သည်"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"ပရိုဖိုင်ပုံများကို လော့ခ်ချထားချိန် ဖန်သားပြင်တွင် ပြပေးသည်"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"ဤစကားဝိုင်းများကို သင့်ပင်မစာမျက်နှာရှိ ပူဖောင်းကွက်များတွင် အလွယ်တကူ ရှာနိုင်ပါသည်"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'မနှောင့်ယှက်ရ\' ကို ကြားဖြတ်ခြင်း"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ok"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ဆက်တင်များ"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ခလုတ်ကို ယာယီဝှက်ရန် အစွန်းသို့ရွှေ့ပါ"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ဘယ်ဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ညာဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ဘယ်ဘက်အောက်ခြေသို့ ရွှေ့ရန်"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ညာဘက်အောက်ခြေသို့ ရွှေ့ရန်"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"အစွန်းသို့ရွှေ့ပြီး ဝှက်ရန်"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"အစွန်းမှရွှေ့ပြီး ပြရန်"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"စက်ထိန်းစနစ်"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ချိတ်ဆက်စက်များအတွက် ထိန်းချုပ်မှုများထည့်ပါ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"စက်ထိန်းစနစ် ထည့်သွင်းခြင်း"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"ပြီးခဲ့သော <xliff:g id="DURATION">%1$s</xliff:g> မပြည့်ခင်"</string>
<string name="over_timestamp" msgid="4765793502859358634">"ပြီးခဲ့သော <xliff:g id="DURATION">%1$s</xliff:g> ကျော်"</string>
<string name="birthday_status" msgid="2596961629465396761">"မွေးနေ့"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> ၏ မွေးနေ့ ဖြစ်ပါသည်"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"မကြာမီလာမည့် မွေးနေ့"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"မကြာမီ <xliff:g id="NAME">%1$s</xliff:g> ၏ မွေးနေ့ ရောက်တော့မည်"</string>
<string name="anniversary_status" msgid="1790034157507590838">"နှစ်ပတ်လည်"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> ၏ နှစ်ပတ်လည်နေ့ ဖြစ်ပါသည်"</string>
<string name="location_status" msgid="1294990572202541812">"တည်နေရာမျှဝေခြင်း"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> က တည်နေရာကို မျှဝေနေသည်"</string>
<string name="new_story_status" msgid="9012195158584846525">"ဝဘ်ပို့စ်အသစ်"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> က ဝဘ်ပို့စ် မျှဝေလိုက်သည်"</string>
<string name="video_status" msgid="4548544654316843225">"ကြည့်ရှုနေသည်"</string>
<string name="audio_status" msgid="4237055636967709208">"နားထောင်နေသည်"</string>
<string name="game_status" msgid="1340694320630973259">"ကစားနေသည်"</string>
<string name="empty_user_name" msgid="3389155775773578300">"မိတ်ဆွေများ"</string>
<string name="empty_status" msgid="5938893404951307749">"ယနေ့ညချတ်လုပ်ကြစို့။"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"အကြောင်းအရာ မကြာမီ ပေါ်လာပါမည်"</string>
<string name="missed_call" msgid="4228016077700161689">"လွတ်သွားသောခေါ်ဆိုမှု"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"မကြာသေးမီက မက်ဆေ့ဂျ်၊ လွတ်သွားသောခေါ်ဆိုမှုနှင့် အခြေအနေအပ်ဒိတ်များကို ကြည့်နိုင်သည်"</string>
<string name="people_tile_title" msgid="6589377493334871272">"စကားဝိုင်း"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> က မက်ဆေ့ဂျ်ပို့လိုက်သည်"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> က ပုံပို့လိုက်သည်"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"သင်၏ ဘက်ထရီမီတာကို ဖတ်ရာတွင် ပြဿနာရှိနေသည်"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"နောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"နှိုးစက်ပေးမထားပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a2e6c48..4afdbd6 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Utvidet skjermdump"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Avvis skjermdumpen"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning av skjermdump"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Øvre grense"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Nedre grense"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skjermopptaker"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Inndatametode"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Sted"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Posisjon av"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokkér Kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Slå av mikrofonen"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameratilgang"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofontilgang"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tilgjengelig"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokkert"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medieenhet"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Bare nødanrop"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skjermopptak"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stopp"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"For å fortsette må <b><xliff:g id="APP">%s</xliff:g></b> ha tilgang til enhetsmikrofonen."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"For å fortsette må <b><xliff:g id="APP">%s</xliff:g></b> ha tilgang til enhetskameraet."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du oppheve blokkeringen av enhetsmikrofonen?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du oppheve blokkeringen av enhetskameraet?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du oppheve blokkeringen av enhetskameraet og -mikrofonen?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke mikrofonen."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke kameraet."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Dette opphever blokkeringen av tilgang for alle apper og tjenester som har tillatelse til å bruke kameraet eller mikrofonen."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Enhet"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Sveip opp for å bytte apper"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Dra til høyre for å bytte apper raskt"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Klar"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Konfigurer betaling"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås opp for å bruke"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Det oppsto et problem med henting av kortene. Prøv igjen senere"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Work-profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flymodus"</string>
<string name="add_tile" msgid="6239678623873086686">"Legg til felt"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Nedgradert til lydløst"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> Rangert høyere"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> Rangert lavere"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Vises alltid øverst i varslene – selv når prioritetsmodus er på"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Innstillinger"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioriterte samtaler"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Denne varselgruppen kan ikke konfigureres her"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Innstillinger for å oppdatere systemnavigeringen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Samtalen er prioritert"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioriterte samtaler"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Disse samtalene vises øverst i listen og kan alltid nå deg når prioritetsmodus er på"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profilbilder vises på låseskjermen"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Det er lett å finne disse samtalene i bobler på startskjermen"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Overstyr «Ikke forstyrr»"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Greit"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Innstillinger"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Bytt"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tilgjengelighet-knappen har erstattet tilgjengelighetsbevegelsen\n\n"<annotation id="link">"Se innstillingene"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytt knappen til kanten for å skjule den midlertidig"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytt til øverst til venstre"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytt til øverst til høyre"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Flytt til nederst til venstre"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flytt til nederst til høyre"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytt til kanten og skjul"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytt ut kanten og vis"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyring"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Legg til kontroller for de tilkoblede enhetene dine"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhetsstyring"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"For mindre enn <xliff:g id="DURATION">%1$s</xliff:g> siden"</string>
<string name="over_timestamp" msgid="4765793502859358634">"For mer enn <xliff:g id="DURATION">%1$s</xliff:g> siden"</string>
<string name="birthday_status" msgid="2596961629465396761">"Bursdag"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> har bursdag"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Bursdag snart"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> har snart bursdag"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Merkedag"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> har merkedag"</string>
<string name="location_status" msgid="1294990572202541812">"Deler posisjonen"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> deler posisjon"</string>
<string name="new_story_status" msgid="9012195158584846525">"Ny nyhetssak"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> har delt nytt innhold"</string>
<string name="video_status" msgid="4548544654316843225">"Ser på"</string>
<string name="audio_status" msgid="4237055636967709208">"Lytter"</string>
<string name="game_status" msgid="1340694320630973259">"Spiller"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Venner"</string>
<string name="empty_status" msgid="5938893404951307749">"La oss chatte senere"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Innhold vises snart"</string>
<string name="missed_call" msgid="4228016077700161689">"Tapt anrop"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Se nylige meldinger, tapte anrop og statusoppdateringer"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Samtale"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en melding"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et bilde"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kunne ikke lese batterimåleren"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trykk for å få mer informasjon"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm angitt"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 36837c0..f575b3a 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"अन्य कुराहरू खिच्नुहोस्"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रिनसट हटाउनुहोस्"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रिनसटको पूर्वावलोकन"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"सिरानको सीमा"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"फेदको सीमा"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रिन रेकर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
@@ -329,7 +335,7 @@
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_header_onboarding_text" msgid="1918085351115504765">"थप विकल्पहरूका लागि आइकनहरूमा टच एण्ड होल्ड गर्नुहोस्"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"बाधा नपुऱ्याउनुहोस्"</string>
- <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"प्राथमिकता मात्र"</string>
+ <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"प्राथमिकता दिइएको मात्र"</string>
<string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"अलार्महरू मात्र"</string>
<string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"पूरै शान्त"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लुटुथ"</string>
@@ -352,8 +358,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"आगत विधि"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"स्थान बन्द छ"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"क्यामेरा ब्लक गर्नुहोस्"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"माइक्रोफोन म्युट गर्नुहोस्"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"मिडिया उपकरण"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"आपत्कालीन कल मात्र"</string>
@@ -366,7 +378,7 @@
<string name="quick_settings_internet_label" msgid="6603068555872455463">"इन्टरनेट"</string>
<string name="quick_settings_networks_available" msgid="1875138606855420438">"उपलब्ध नेटवर्कहरू"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"नेटवर्क उपलब्ध छैन"</string>
- <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"जोडिएको छैन"</string>
+ <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"कनेक्ट गरिएको छैन"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"नेटवर्क छैन"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi बन्द"</string>
<string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"Wi-Fi सक्रिय छ"</string>
@@ -425,8 +437,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्रिनको रेकर्ड"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरु गर्नुहोस्"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोक्नुहोस्"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"जारी राख्न <b><xliff:g id="APP">%s</xliff:g></b> लाई तपाईंको डिभाइसको माइक्रोफोन प्रयोग गर्ने अनुमति दिनु पर्ने हुन्छ।"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"जारी राख्न <b><xliff:g id="APP">%s</xliff:g></b> लाई तपाईंको डिभाइसको क्यामेरा प्रयोग गर्ने अनुमति दिनु पर्ने हुन्छ।"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"यन्त्र"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"एपहरू बदल्न माथितिर स्वाइप गर्नुहोस्"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"एपहरू बदल्न द्रुत गतिमा दायाँतिर ड्र्याग गर्नुहोस्"</string>
@@ -458,7 +480,7 @@
<string name="camera_hint" msgid="4519495795000658637">"क्यामेराको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
<string name="interruption_level_none_with_warning" msgid="8394434073508145437">"पूर्ण शान्त। यसले पनि स्क्रिन बाचकलाई शान्त गराउँछ।"</string>
<string name="interruption_level_none" msgid="219484038314193379">"पूरै शान्त"</string>
- <string name="interruption_level_priority" msgid="661294280016622209">"प्राथमिकता मात्र"</string>
+ <string name="interruption_level_priority" msgid="661294280016622209">"प्राथमिकता दिइएको मात्र"</string>
<string name="interruption_level_alarms" msgid="2457850481335846959">"अलार्महरू मात्र"</string>
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"पूरै\nशान्त"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"प्राथमिकता \nमात्र"</string>
@@ -500,7 +522,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"प्रदर्शन र ब्याकग्राउन्ड डेटा घटाउँनुहोस्"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ब्याट्री सेभर अफ गर्नुहोस्"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य प्रदान गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा कास्ट गर्दा तपाईंको डिभाइसबाट प्ले गरिएका कुरा हेर्न तथा प्रयोग गर्न सक्छ। यसले हेर्न तथा प्रयोग गर्न सक्ने कुरामा पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो कुराहरू समावेश हुन सक्छन्।"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मार्फत रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"फेरि नदेखाउनुहोस्"</string>
@@ -660,9 +682,9 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"इथरनेट"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"अलार्म"</string>
<string name="wallet_title" msgid="5369767670735827105">"वालेट"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
<!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
<skip />
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index e6c5bd0..8f88950 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -33,7 +33,6 @@
<!-- The color of the text inside a notification -->
<color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color>
- <color name="notif_pill_background">@*android:color/surface_dark</color>
<color name="notif_pill_text">@android:color/system_neutral1_50</color>
<color name="notification_guts_link_icon_tint">@color/GM2_grey_500</color>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index fdf0e9b..3169795 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Meer opnemen"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot sluiten"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Voorbeeld van screenshot"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Bovengrens"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Ondergrens"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Schermopname"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Invoermethode"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locatie"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Locatie uit"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Camera blokkeren"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Microfoon uitzetten"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Cameratoegang"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Microfoontoegang"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Beschikbaar"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Geblokkeerd"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media-apparaat"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Alleen noodoproepen"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Schermopname"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppen"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"<b><xliff:g id="APP">%s</xliff:g></b> heeft toegang tot de microfoon van je apparaat nodig om door te gaan."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"<b><xliff:g id="APP">%s</xliff:g></b> heeft toegang tot de camera van je apparaat nodig om door te gaan."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blokkeren van apparaatmicrofoon opheffen?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Blokkeren van apparaatcamera opheffen?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blokkeren van apparaatcamera en -microfoon opheffen?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je microfoon te gebruiken."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je camera te gebruiken."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Hiermee hef je de toegangsblokkering op voor alle apps en services die rechten hebben om je camera of microfoon te gebruiken."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Apparaat"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe omhoog om te schakelen tussen apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Sleep naar rechts om snel tussen apps te schakelen"</string>
@@ -551,7 +563,7 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Je organisatie heeft een certificeringsinstantie geïnstalleerd in je werkprofiel. Je beveiligde netwerkverkeer kan worden bijgehouden of aangepast."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Er is een certificeringsinstantie geïnstalleerd op dit apparaat. Je beveiligde netwerkverkeer kan worden bijgehouden of aangepast."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Je beheerder heeft de netwerkregistratie aangezet, waarmee het verkeer op je apparaat wordt gecontroleerd."</string>
- <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Je beheerder heeft logboekregistratie voor het netwerk aangezet. Hiermee wordt verkeer in je werkprofiel bijgehouden, maar niet in je persoonlijke profiel."</string>
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Je beheerder heeft netwerkregistratie aangezet. Hiermee wordt verkeer in je werkprofiel bijgehouden, maar niet in je persoonlijke profiel."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Je bent verbonden met <xliff:g id="VPN_APP">%1$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden gecontroleerd."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Je bent verbonden met <xliff:g id="VPN_APP_0">%1$s</xliff:g> en <xliff:g id="VPN_APP_1">%2$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden bijgehouden."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Je werkprofiel is verbonden met <xliff:g id="VPN_APP">%1$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden bijgehouden."</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Wekker"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Alles tonen"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Ontgrendelen om te betalen"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Klaar"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Betaling instellen"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index cc9cad2..f3daff5 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ଅଧିକ କ୍ୟାପଚର୍ କରନ୍ତୁ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ସ୍କ୍ରିନସଟ୍ ଖାରଜ କରନ୍ତୁ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ସ୍କ୍ରିନସଟର ପ୍ରିଭ୍ୟୁ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ଶୀର୍ଷ ସୀମାରେଖା"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ନିମ୍ନ ସୀମାରେଖା"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ସ୍କ୍ରିନ୍ ରେକର୍ଡର୍"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରିନ୍ ରେକର୍ଡ୍ ସେସନ୍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ଇନପୁଟ୍ ପଦ୍ଧତି"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ଲୋକେସନ୍"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ଲୋକେସନ୍ ଅଫ୍"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"କ୍ୟାମେରାକୁ ବ୍ଲକ୍ କରନ୍ତୁ"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"ମାଇକ୍ରୋଫୋନକୁ ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"କ୍ୟାମେରା ଆକ୍ସେସ୍"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"ମାଇକ୍ ଆକ୍ସେସ୍"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ଉପଲବ୍ଧ"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ବ୍ଲକ୍ କରାଯାଇଛି"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ମିଡିଆ ଡିଭାଇସ୍"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"କେବଳ ଜରୁରୀକାଳୀନ କଲ୍"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ସ୍କ୍ରିନ୍ ରେକର୍ଡ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ବନ୍ଦ କରନ୍ତୁ"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ଜାରି ରଖିବାକୁ, <b><xliff:g id="APP">%s</xliff:g></b> ଆପଣଙ୍କ ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଆକ୍ସେସ୍ ଆବଶ୍ୟକ କରେ।"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ଜାରି ରଖିବାକୁ, <b><xliff:g id="APP">%s</xliff:g></b> ଆପଣଙ୍କ ଡିଭାଇସର କ୍ୟାମେରାକୁ ଆକ୍ସେସ୍ ଆବଶ୍ୟକ କରେ।"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ଡିଭାଇସର କ୍ୟାମେରାକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ଡିଭାଇସର କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"ଆପଣଙ୍କ ମାଇକ୍ରୋଫୋନକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"ଆପଣଙ୍କ କ୍ୟାମେରାକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"ଆପଣଙ୍କ କ୍ୟାମେରା କିମ୍ବା ମାଇକ୍ରୋଫୋନକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଅନୁମତି ଦିଆଯାଇଥିବା ସମସ୍ତ ଆପ୍ ଓ ସେବା ପାଇଁ ଏହା ଆକ୍ସେସକୁ ଅନବ୍ଲକ୍ କରେ।"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"ଡିଭାଇସ୍"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ଆପ୍କୁ ବଦଳ କରିବା ପାଇଁ ସ୍ଵାଇପ୍ କରନ୍ତୁ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ଆପ୍ଗୁଡ଼ିକ ମଧ୍ୟରେ ଶୀଘ୍ର ବଦଳ କରିବା ପାଇଁ ଡାହାଣକୁ ଡ୍ରାଗ୍ କରନ୍ତୁ"</string>
@@ -497,7 +509,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"କାର୍ଯ୍ୟ ସମ୍ପାଦନ ଓ ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଡାଟା କମ୍ କରନ୍ତୁ"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ବ୍ୟାଟେରୀ ସେଭର୍ ଅଫ୍ କରନ୍ତୁ"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ରେ ସମସ୍ତ ସୂଚନାକୁ ଆକ୍ସେସ୍ ରହିବ ଯାହା ଆପଣଙ୍କର ସ୍କ୍ରିନ୍ରେ ଦେଖାଯିବ ବା ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ବେଳେ ଆପଣଙ୍କର ଡିଭାଇସ୍ ଠାରୁ ଚାଲିବ। ପାସ୍ୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ଫଟୋ, ମେସେଜ୍ ଏବଂ ଆପଣ ଚଲାଉଥିବା ଅଡିଓ ପରି ସୂଚନା ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି।"</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ବେଳେ ଆପଣଙ୍କର ଡିଭାଇସରେ ଦେଖାଯାଉଥିବା ବା ଆପଣଙ୍କ ଡିଭାଇସରୁ ପ୍ଲେ କରାଯାଉଥିବା ସବୁ ସୂଚନାକୁ ଏହି ପ୍ରକାର୍ଯ୍ୟ ପ୍ରଦାନ କରୁଥିବା ସେବାର ଆକସେସ୍ ରହିବ। ପାସ୍ୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ଫଟୋ, ମେସେଜ୍ ଏବଂ ଆପଣ ଚଲାଉଥିବା ଅଡିଓ ପରି ସୂଚନା ଏଥିରେ ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି।"</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ବେଳେ ଆପଣଙ୍କର ଡିଭାଇସରେ ଦେଖାଯାଉଥିବା ବା ଆପଣଙ୍କ ଡିଭାଇସରୁ ପ୍ଲେ କରାଯାଉଥିବା ସବୁ ସୂଚନାକୁ ଏହି ଫଙ୍କସନ୍ ପ୍ରଦାନ କରୁଥିବା ସେବାର ଆକ୍ସେସ୍ ରହିବ। ପାସ୍ୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ଫଟୋ, ମେସେଜ୍ ଏବଂ ଆପଣ ଚଲାଉଥିବା ଅଡିଓ ପରି ସୂଚନା ଏଥିରେ ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି।"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ଆରମ୍ଭ କରିବେ?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ସହ ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ଆରମ୍ଭ କରିବେ?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ଇଥରନେଟ୍"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"ଆଲାର୍ମ"</string>
<string name="wallet_title" msgid="5369767670735827105">"ୱାଲେଟ୍"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"ପ୍ରସ୍ତୁତ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ପେମେଣ୍ଟ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"ଆପଣଙ୍କ କାର୍ଡଗୁଡ଼ିକ ପାଇବାରେ ଏକ ସମସ୍ୟା ହୋଇଥିଲା। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
<string name="status_bar_work" msgid="5238641949837091056">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍"</string>
<string name="add_tile" msgid="6239678623873086686">"ଟାଇଲ୍ ଯୋଡ଼ନ୍ତୁ"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ସ୍ଥିତି:</b> ନୀରବକୁ ଡିମୋଟ୍ କରାଯାଇଛି"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>ସ୍ଥିତି:</b> ରେଙ୍କ ଉପରକୁ କରାଯାଇଛି"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>ସ୍ଥିତି:</b> ରେଙ୍କ ତଳକୁ କରାଯାଇଛି"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"ଆପଣଙ୍କ ପ୍ରାଥମିକତା ମୋଡ୍ ଚାଲୁ ଥିବା ସମୟରେ ମଧ୍ୟ ସର୍ବଦା ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଦେଖାଯାଇଥାଏ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ସେଟିଂସ୍"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"ପ୍ରାଥମିକତା ଦିଆଯାଇଥିବା ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ଏଠାରେ ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଗ୍ରୁପ୍ କନଫ୍ୟୁଗର୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍ଡେଟ୍ କରିବା ପାଇଁ ସେଟିଂସ୍କୁ ଯାଆନ୍ତୁ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"ବାର୍ତ୍ତାଳାପ ପ୍ରାଥମିକତାରେ ସେଟ୍ କରାଯାଇଛି"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"ପ୍ରାଥମିକତା ଦିଆଯାଇଥିବା ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ଏହି ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଆପଣଙ୍କ ତାଲିକାର ଶୀର୍ଷରେ ଦେଖାଯାଏ ଏବଂ ପ୍ରାଥମିକତା ମୋଡ୍ ଚାଲୁ ଥିବା ସମୟରେ ସର୍ବଦା ଆପଣଙ୍କ ନିକଟରେ ପହଞ୍ଚିପାରିବ"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"ପ୍ରୋଫାଇଲ୍ ଛବିଗୁଡ଼ିକ ଲକ୍ ସ୍କ୍ରିନରେ ଦେଖାଯାଏ"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"ଆପଣ ଆପଣଙ୍କ ମୂଳସ୍କ୍ରିନରେ ଥିବା ବବଲଗୁଡ଼ିକରେ ଏହି ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକୁ ସହଜରେ ପାଇପାରିବେ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ମୋଡରେ ବାଧା"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ବୁଝିଗଲି"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ସେଟିଂସ୍"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ବଟନକୁ ଅସ୍ଥାୟୀ ଭାବେ ଲୁଚାଇବା ପାଇଁ ଧାରକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ଶୀର୍ଷ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ଶୀର୍ଷ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ନିମ୍ନ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ନିମ୍ନ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ଧାରକୁ ମୁଭ୍ କରି ଲୁଚାନ୍ତୁ"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ଧାର ବାହାରକୁ ମୁଭ୍ କରି ଦେଖାନ୍ତୁ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ଆପଣଙ୍କ ସଂଯୁକ୍ତ ଡିଭାଇସଗୁଡ଼ିକ ପାଇଁ ନିୟନ୍ତ୍ରଣ ଯୋଗ କରନ୍ତୁ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>ରୁ କମ୍ ସମୟ ପୂର୍ବେ"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>ରୁ ଅଧିକ ସମୟ ପୂର୍ବେ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ଜନ୍ମଦିନ"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"ଆଜି <xliff:g id="NAME">%1$s</xliff:g>ଙ୍କ ଜନ୍ମଦିନ"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ଜନ୍ମଦିନ ଶୀଘ୍ର ଆସୁଛି"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g>ଙ୍କ ଜନ୍ମଦିନ ଶୀଘ୍ର ଆସୁଛି"</string>
<string name="anniversary_status" msgid="1790034157507590838">"ବାର୍ଷିକ ଉତ୍ସବ"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"ଆଜି <xliff:g id="NAME">%1$s</xliff:g>ଙ୍କ ବାର୍ଷିକ ଉତ୍ସବ"</string>
<string name="location_status" msgid="1294990572202541812">"ଲୋକେସନ୍ ସେୟାର୍ ହେଉଛି"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> ଲୋକେସନ୍ ସେୟାର୍ କରୁଛନ୍ତି"</string>
<string name="new_story_status" msgid="9012195158584846525">"ନୂଆ ଷ୍ଟୋରୀ"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ନୂଆ ଷ୍ଟୋରୀ ସେୟାର୍ କରିଛନ୍ତି"</string>
<string name="video_status" msgid="4548544654316843225">"ଦେଖୁଛନ୍ତି"</string>
<string name="audio_status" msgid="4237055636967709208">"ଶୁଣୁଛି"</string>
<string name="game_status" msgid="1340694320630973259">"ଚାଲୁଛି"</string>
<string name="empty_user_name" msgid="3389155775773578300">"ସାଙ୍ଗମାନେ"</string>
<string name="empty_status" msgid="5938893404951307749">"ରାତିରେ ଚାଟ୍ କରିବା!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"ବିଷୟବସ୍ତୁ ଶୀଘ୍ର ଦେଖାଯିବ"</string>
<string name="missed_call" msgid="4228016077700161689">"ମିସ୍ଡ କଲ୍"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ବର୍ତ୍ତମାନର ମେସେଜ୍, ମିସ୍ଡ କଲ୍ ଏବଂ ସ୍ଥିତି ଅପଡେଟଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ବାର୍ତ୍ତାଳାପ"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ମେସେଜ୍ ପଠାଇଛନ୍ତି"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ଛବି ପଠାଇଛନ୍ତି"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ମିଟର୍ ପଢ଼ିବାରେ ସମସ୍ୟା ହେଉଛି"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ଆଲାର୍ମ ସେଟ୍ ହୋଇନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3de8716..6fba7a4 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"ਹੋਰ ਕੈਪਚਰ ਕਰੋ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਪੂਰਵ-ਝਲਕ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ਉੱਪਰ ਦੀ ਸੀਮਾ"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ਹੇਠਾਂ ਦੀ ਸੀਮਾ"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ਇਨਪੁੱਟ ਵਿਧੀ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ਟਿਕਾਣਾ"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਬੰਦ"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"ਕੈਮਰਾ ਬਲਾਕ ਕਰੋ"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਮਿਊਟ ਕਰੋ"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ਮੀਡੀਆ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ਸਿਰਫ਼ ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ਰੋਕੋ"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"ਜਾਰੀ ਰੱਖਣ ਲਈ, <b><xliff:g id="APP">%s</xliff:g></b> ਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਤੱਕ ਪਹੁੰਚ ਦੀ ਲੋੜ ਹੈ।"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"ਜਾਰੀ ਰੱਖਣ ਲਈ, <b><xliff:g id="APP">%s</xliff:g></b> ਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰਾ ਤੱਕ ਪਹੁੰਚ ਦੀ ਲੋੜ ਹੈ।"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"ਡੀਵਾਈਸ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ਐਪਾਂ ਵਿਚਾਲੇ ਤੇਜ਼ੀ ਨਾਲ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਘਸੀਟੋ"</string>
@@ -497,8 +519,8 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"ਪ੍ਰਦਰਸ਼ਨ ਅਤੇ ਪਿਛੋਕੜ ਡਾਟਾ ਘੱਟ ਕਰਦਾ ਹੈ"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ਬੈਟਰੀ ਸੇਵਰ ਬੰਦ ਕਰੋ"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਕੋਲ ਬਾਕੀ ਸਾਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ ਜੋ ਕਿ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣਯੋਗ ਹੈ ਜਾਂ ਰਿਕਾਰਡਿੰਗ ਜਾਂ ਕਾਸਟ ਕਰਨ ਵੇਲੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਵਿੱਚ ਪਾਸਵਰਡ, ਭੁਗਤਾਨ ਵੇਰਵੇ, ਫ਼ੋਟੋਆਂ, ਸੁਨੇਹੇ ਅਤੇ ਤੁਹਾਡੇ ਵੱਲੋਂ ਚਲਾਏ ਆਡੀਓ ਦੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ।"</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ਇਸ ਫੰਕਸ਼ਨ ਦੇ ਸੇਵਾ ਪ੍ਰਦਾਨਕ ਕੋਲ ਬਾਕੀ ਸਾਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ ਜੋ ਕਿ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣਯੋਗ ਹੁੰਦੀ ਹੈ ਜਾਂ ਰਿਕਾਰਡਿੰਗ ਜਾਂ ਕਾਸਟ ਕਰਨ ਵੇਲੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਵਿੱਚ ਪਾਸਵਰਡ, ਭੁਗਤਾਨ ਵੇਰਵੇ, ਫ਼ੋਟੋਆਂ, ਸੁਨੇਹੇ ਅਤੇ ਤੁਹਾਡੇ ਵੱਲੋਂ ਚਲਾਏ ਆਡੀਓ ਦੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ।"</string>
- <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ਕੀ ਰਿਕਾਰਡਿੰਗ ਜਾਂ ਕਾਸਟ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ?"</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ਇਹ ਫੰਕਸ਼ਨ ਪ੍ਰਦਾਨ ਕਰਨ ਵਾਲੀ ਸੇਵਾ ਕੋਲ ਸਾਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ ਜੋ ਕਿ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣਯੋਗ ਹੁੰਦੀ ਹੈ ਜਾਂ ਰਿਕਾਰਡ ਜਾਂ ਕਾਸਟ ਕਰਨ ਵੇਲੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਵਿੱਚ ਪਾਸਵਰਡ, ਭੁਗਤਾਨ ਵੇਰਵੇ, ਫ਼ੋਟੋਆਂ, ਸੁਨੇਹੇ ਅਤੇ ਤੁਹਾਡੇ ਵੱਲੋਂ ਚਲਾਏ ਆਡੀਓ ਦੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ।"</string>
+ <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ਕੀ ਰਿਕਾਰਡ ਜਾਂ ਕਾਸਟ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਨਾਲ ਰਿਕਾਰਡਿੰਗ ਜਾਂ ਕਾਸਟ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ਈਥਰਨੈਟ"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"ਅਲਾਰਮ"</string>
<string name="wallet_title" msgid="5369767670735827105">"ਵਾਲੇਟ"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"ਤਿਆਰ"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ਭੁਗਤਾਨ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"ਤੁਹਾਡੇ ਕਾਰਡ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆਈ, ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="status_bar_work" msgid="5238641949837091056">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string>
<string name="add_tile" msgid="6239678623873086686">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ਸਥਿਤੀ:</b> ਦਰਜਾ ਘਟਾ ਕੇ ਸ਼ਾਂਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>ਸਥਿਤੀ:</b> ਦਰਜਾ ਵਧਾਇਆ ਗਿਆ"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>ਸਥਿਤੀ:</b> ਦਰਜਾ ਘਟਾਇਆ ਗਿਆ"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"ਹਮੇਸ਼ਾਂ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ, ਭਾਵੇਂ ਤਰਜੀਹ ਮੋਡ ਚਾਲੂ ਹੋਵੇ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"ਤਰਜੀਹੀ ਗੱਲਾਂਬਾਤਾਂ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ਇਹ ਸੂਚਨਾਵਾਂ ਦਾ ਗਰੁੱਪ ਇੱਥੇ ਸੰਰੂਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"ਗੱਲਬਾਤ ਨੂੰ ਤਰਜੀਹੀ ਗੱਲਬਾਤ ਵਜੋਂ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"ਤਰਜੀਹੀ ਗੱਲਾਂਬਾਤਾਂ"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"ਇਹ ਗੱਲਾਂਬਾਤਾਂ ਤੁਹਾਡੀ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ ਅਤੇ ਤਰਜੀਹ ਮੋਡ ਚਾਲੂ ਹੋਣ \'ਤੇ ਹਮੇਸ਼ਾਂ ਤੁਹਾਡੇ ਤੱਕ ਪਹੁੰਚ ਸਕਦੀਆਂ ਹਨ"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰਾਂ ਨੂੰ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"ਤੁਸੀਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਬੁਲਬੁਲਿਆਂ ਵਿੱਚ ਇਹਨਾਂ ਗੱਲਾਂਬਾਤਾਂ ਨੂੰ ਆਸਾਨੀ ਨਾਲ ਲੱਭ ਸਕਦੇ ਹੋ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਵਿਘਨ ਪੈ ਸਕਦਾ ਹੈ"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ਸਮਝ ਲਿਆ"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ਸੈਟਿੰਗਾਂ"</string>
@@ -1040,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ਬਟਨ ਨੂੰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਲੁਕਾਉਣ ਲਈ ਕਿਨਾਰੇ \'ਤੇ ਲਿਜਾਓ"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ਉੱਪਰ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ਕਿਨਾਰੇ ਵਿੱਚ ਲਿਜਾ ਕੇ ਲੁਕਾਓ"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ਕਿਨਾਰੇ ਤੋਂ ਬਾਹਰ ਕੱਢ ਕੇ ਦਿਖਾਓ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ਡੀਵਾਈਸ ਕੰਟਰੋਲ"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ਆਪਣੇ ਕਨੈਕਟ ਕੀਤੇ ਡੀਵਾਈਸਾਂ ਲਈ ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਦਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> ਤੋਂ ਘੱਟ ਸਮਾਂ ਪਹਿਲਾਂ"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> ਤੋਂ ਵੱਧ ਸਮਾਂ ਪਹਿਲਾਂ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ਜਨਮਦਿਨ"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"ਅੱਜ <xliff:g id="NAME">%1$s</xliff:g> ਦਾ ਜਨਮਦਿਨ ਹੈ"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ਜਨਮਦਿਨ ਜਲਦ ਆ ਰਿਹਾ ਹੈ"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> ਦਾ ਜਨਮਦਿਨ ਜਲਦ ਆ ਰਿਹਾ ਹੈ"</string>
<string name="anniversary_status" msgid="1790034157507590838">"ਵਰ੍ਹੇਗੰਢ"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"ਅੱਜ <xliff:g id="NAME">%1$s</xliff:g> ਦੀ ਵਰ੍ਹੇਗੰਢ ਹੈ"</string>
<string name="location_status" msgid="1294990572202541812">"ਟਿਕਾਣਾ ਸਾਂਝਾ ਹੋ ਰਿਹਾ ਹੈ"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਟਿਕਾਣਾ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="new_story_status" msgid="9012195158584846525">"ਨਵੀਂ ਕਹਾਣੀ"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਇੱਕ ਨਵੀਂ ਕਹਾਣੀ ਸਾਂਝੀ ਕੀਤੀ"</string>
<string name="video_status" msgid="4548544654316843225">"ਦੇਖਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="audio_status" msgid="4237055636967709208">"ਸੁਣਿਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="game_status" msgid="1340694320630973259">"ਖੇਡੀ ਜਾ ਰਹੀ ਹੈ"</string>
<string name="empty_user_name" msgid="3389155775773578300">"ਦੋਸਤ"</string>
<string name="empty_status" msgid="5938893404951307749">"ਆਓ ਅੱਜ ਰਾਤ ਚੈਟ ਕਰੀਏ!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"ਸਮੱਗਰੀ ਜਲਦ ਦਿਖਾਈ ਜਾਵੇਗੀ"</string>
<string name="missed_call" msgid="4228016077700161689">"ਮਿਸ ਕਾਲ"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ਹਾਲੀਆ ਸੁਨੇਹੇ, ਮਿਸ ਕਾਲਾਂ ਅਤੇ ਸਥਿਤੀ ਸੰਬੰਧੀ ਅੱਪਡੇਟ ਦੇਖੋ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ਗੱਲਬਾਤ"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਇੱਕ ਸੁਨੇਹਾ ਭੇਜਿਆ"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਇੱਕ ਚਿੱਤਰ ਭੇਜਿਆ ਹੈ"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ਤੁਹਾਡੇ ਬੈਟਰੀ ਮੀਟਰ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਸਮੱਸਿਆ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ਕੋਈ ਅਲਾਰਮ ਸੈੱਟ ਨਹੀਂ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index cc0c6d5..bd82a00 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Zarejestruj więcej danych"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zamknij zrzut ekranu"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Podgląd zrzutu ekranu"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Górna granica"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Dolna granica"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metoda wprowadzania"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokalizacja"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokalizacja wyłączona"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Zablokuj aparat"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Wycisz mikrofon"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Dostęp do aparatu"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Dostęp do mikrofonu"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Dostępny"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Zablokowany"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Urządzenie multimedialne"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Tylko połączenia alarmowe"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Nagrywanie ekranu"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Rozpocznij"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zatrzymaj"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Aby kontynuować, musisz przyznać aplikacji „<xliff:g id="APP">%s</xliff:g>” dostęp do mikrofonu urządzenia."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Aby kontynuować, musisz przyznać aplikacji „<xliff:g id="APP">%s</xliff:g>” dostęp do aparatu urządzenia."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokować mikrofon urządzenia?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokować aparat urządzenia?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokować aparat i mikrofon urządzenia?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z mikrofonu."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z aparatu."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Spowoduje to odblokowanie dostępu dla wszystkich aplikacji i usług, które mają uprawnienia do korzystania z aparatu lub mikrofonu."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Urządzenie"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Przesuń w górę, by przełączyć aplikacje"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Szybko przeciągnij w prawo, by przełączyć aplikacje"</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Portfel"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Gotowe"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Skonfiguruj płatność"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odblokuj, aby użyć"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Podczas pobierania kart wystąpił problem. Spróbuj ponownie później."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil służbowy"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Tryb samolotowy"</string>
<string name="add_tile" msgid="6239678623873086686">"Dodaj nazwę"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stan:</b> zmieniono na Ciche"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Stan:</b> podniesiono ważność"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Stan:</b> obniżono ważność"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Zawsze pokazywane u góry powiadomień, nawet po włączeniu trybu Priorytet"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ustawienia"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Rozmowy priorytetowe"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Tej grupy powiadomień nie można tu skonfigurować"</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Otwórz Ustawienia, by zaktualizować nawigację w systemie"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Rozmowę ustawiono jako priorytetową"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Rozmowy priorytetowe"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Te rozmowy są pokazywane na początku listy i nie przegapisz ich, jeśli włączysz tryb Priorytet"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Zdjęcia profilowe są widoczne na ekranie blokady"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Łatwo znajdziesz te rozmowy w dymkach na ekranie głównym"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ignorują tryb Nie przeszkadzać"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ustawienia"</string>
@@ -1050,18 +1052,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Przełącz"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Przycisk ułatwień dostępu zastąpił gest ułatwień dostępu\n\n"<annotation id="link">"Wyświetl ustawienia"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Przesuń przycisk do krawędzi, aby ukryć go tymczasowo"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Przenieś w lewy górny róg"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Przenieś w prawy górny róg"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Przenieś w lewy dolny róg"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Przenieś w prawy dolny róg"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Przenieś do krawędzi i ukryj"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Przenieś poza krawędź i pokaż"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniami"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodaj elementy sterujące połączonymi urządzeniami"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurowanie sterowania urządzeniami"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Mniej niż <xliff:g id="DURATION">%1$s</xliff:g> temu"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Ponad <xliff:g id="DURATION">%1$s</xliff:g> temu"</string>
<string name="birthday_status" msgid="2596961629465396761">"Urodziny"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> ma urodziny"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Wkrótce urodziny"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> będzie mieć wkrótce urodziny"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Rocznica"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> ma rocznicę"</string>
<string name="location_status" msgid="1294990572202541812">"Udostępniam lokalizację"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> udostępnia lokalizację"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nowy artykuł"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> udostępnia nową relację"</string>
<string name="video_status" msgid="4548544654316843225">"Oglądam"</string>
<string name="audio_status" msgid="4237055636967709208">"Słucham"</string>
<string name="game_status" msgid="1340694320630973259">"Odtwarzam"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Znajomi"</string>
<string name="empty_status" msgid="5938893404951307749">"Porozmawiajmy!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Treść wkrótce będzie widoczna"</string>
<string name="missed_call" msgid="4228016077700161689">"Nieodebrane połączenie"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Zobacz ostatnie wiadomości, nieodebrane połączenia i stany"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Rozmowa"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> wysyła wiadomość"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> wysyła zdjęcie"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem z odczytaniem pomiaru wykorzystania baterii"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Kliknij, aby uzyskać więcej informacji"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nie ustawiono alarmu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 5b1f72e..e0be916 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Limite superior"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Limite inferior"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização desativada"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear câmera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Desativar microfone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chamadas de emergência"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravação de tela"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Para continuar, o app <b><xliff:g id="APP">%s</xliff:g></b> precisa acessar o microfone do dispositivo."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Para continuar, o app <b><xliff:g id="APP">%s</xliff:g></b> precisa acessar a câmera do dispositivo."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Essa ação desbloqueia o acesso de todos os apps e serviços com autorização para usar seu microfone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Essa ação desbloqueia o acesso de todos os apps e serviços com autorização para usar sua câmera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Essa ação desbloqueia o acesso de todos os apps e serviços com autorização para usar sua câmera ou seu microfone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslize para cima para alternar entre os apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para alternar rapidamente entre os apps"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
<string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Mostrar tudo"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Desbloquear para pagar"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Pronto"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurar o pagamento"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 602f3ce..e86ca3e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar captura de ecrã"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pré-visualização da captura de ecrã"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Limite superior"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Limite inferior"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de ecrã"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"A processar a gravação de ecrã"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação persistente de uma sessão de gravação de ecrã"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de Introdução"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização Desativada"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear a câmara"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Desativar o som do microfone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmara"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimédia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Apenas chamadas de emergência"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravação de ecrã"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Para continuar, a app <b><xliff:g id="APP">%s</xliff:g></b> precisa de acesso ao microfone do dispositivo."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Para continuar, a app <b><xliff:g id="APP">%s</xliff:g></b> precisa de acesso à câmara do dispositivo."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Pretende desbloquear o microfone do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Pretende desbloquear a câmara do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Pretende desbloquear a câmara e o microfone?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar o seu microfone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar a sua câmara."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Isto desbloqueia o acesso a todas as apps e serviços com autorização para utilizar a sua câmara ou microfone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslizar rapidamente para cima para mudar de app"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para mudar rapidamente de app."</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
<string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Pronto"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurar pagamento"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para utilizar"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente novamente mais tarde."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avião"</string>
<string name="add_tile" msgid="6239678623873086686">"Adicionar mosaico"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> despromovida para Silenciosa"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Estado:</b> passou para classificação superior"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Estado:</b> passou para classificação inferior"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Apresentadas sempre no topo das suas notificações, mesmo quando o modo Prioridade está ativado"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Definições"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversas com prioridade"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta funcionalidades de conversa."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar este grupo de notificações aqui."</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Aceda às Definições para atualizar a navegação no sistema."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Conversa definida como prioritária"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversas com prioridade"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Estas conversas são apresentadas no topo da sua lista e recebe-as sempre quando o modo Prioridade está ativado"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"As imagens de perfil são apresentadas no ecrã de bloqueio"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Pode encontrar facilmente estas conversas em balões no seu ecrã principal"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompem o modo Não incomodar."</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Definições"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Mudar"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botão Acessibilidade substituiu o gesto de acessibilidade\n\n"<annotation id="link">"Ver definições"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a extremidade para o ocultar temporariamente"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover p/ parte sup. esquerda"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover parte superior direita"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover p/ parte infer. esquerda"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover parte inferior direita"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover p/ extremidade e ocultar"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Retirar extremidade e mostrar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adicione controlos para os dispositivos associados."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configure os controlos de dispositivos"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Há menos de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Há mais de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversário"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"É o aniversário de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversário em breve"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"O aniversário de <xliff:g id="NAME">%1$s</xliff:g> é em breve"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Aniversário"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"É o aniversário de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"A partilhar localiz."</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> está a partilhar a localização"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nova notícia"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> publicou uma nova história"</string>
<string name="video_status" msgid="4548544654316843225">"A ver"</string>
<string name="audio_status" msgid="4237055636967709208">"A ouvir"</string>
<string name="game_status" msgid="1340694320630973259">"Em reprodução"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Amigos"</string>
<string name="empty_status" msgid="5938893404951307749">"Vamos conversar!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Será apresentado conteúdo em breve"</string>
<string name="missed_call" msgid="4228016077700161689">"Chamada não atendida"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Veja mensagens recentes, chamadas não atendidas e atualizações de estado"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ocorreu um problema ao ler o medidor da bateria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para obter mais informações"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nenhum alarme defin."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5b1f72e..e0be916 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Capturar mais"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Limite superior"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Limite inferior"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização desativada"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear câmera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Desativar microfone"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chamadas de emergência"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravação de tela"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Para continuar, o app <b><xliff:g id="APP">%s</xliff:g></b> precisa acessar o microfone do dispositivo."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Para continuar, o app <b><xliff:g id="APP">%s</xliff:g></b> precisa acessar a câmera do dispositivo."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Essa ação desbloqueia o acesso de todos os apps e serviços com autorização para usar seu microfone."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Essa ação desbloqueia o acesso de todos os apps e serviços com autorização para usar sua câmera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Essa ação desbloqueia o acesso de todos os apps e serviços com autorização para usar sua câmera ou seu microfone."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispositivo"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Deslize para cima para alternar entre os apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Arraste para a direita para alternar rapidamente entre os apps"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
<string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Mostrar tudo"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Desbloquear para pagar"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Pronto"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurar o pagamento"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index f68d6ac..0729f69 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Surprindeți mai mult"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Închideți captura de ecran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Previzualizare a capturii de ecran"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Marginea superioară"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Marginea inferioară"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder pentru ecran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificare în curs pentru o sesiune de înregistrare a ecranului"</string>
@@ -350,8 +356,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metodă de introducere"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Locație"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localizarea este dezactivată"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blocați camera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Dezactivați sunetul microfonului"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acces la cameră"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acces la microfon"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponibil"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blocat"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispozitiv media"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Numai apeluri de urgență"</string>
@@ -424,8 +432,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Înregistrarea ecranului"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Începeți"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Opriți"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Pentru a continua, <b><xliff:g id="APP">%s</xliff:g></b> necesită acces la microfonul dispozitivului."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Pentru a continua, <b><xliff:g id="APP">%s</xliff:g></b> necesită acces la camera dispozitivului."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblocați microfonul dispozitivului?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblocați camera dispozitivului?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblocați camera și microfonul dispozitivului?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi microfonul."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera sau microfonul."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Dispozitiv"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Glisați în sus pentru a comuta între aplicații"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Glisați la dreapta pentru a comuta rapid între aplicații"</string>
@@ -660,18 +672,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarmă"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Gata"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Configurați o metodă de plată"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Deblocați pentru a folosi"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"A apărut o problemă la preluarea cardurilor. Încercați din nou mai târziu"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string>
<string name="add_tile" msgid="6239678623873086686">"Adăugați o casetă"</string>
@@ -740,11 +748,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stare:</b> setată ca Silențioasă"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Stare:</b> clasificată mai sus"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Stare:</b> clasificată mai jos"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Se afișează întotdeauna în partea de sus a notificărilor, chiar și când modul Cu prioritate este activat"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setări"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Conversații cu prioritate"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Acest grup de notificări nu poate fi configurat aici"</string>
@@ -1020,14 +1026,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accesați Setările pentru a actualiza navigarea în sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Conversația a fost setată ca prioritară"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Conversații cu prioritate"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Aceste conversații se afișează în partea de sus a listei și apar chiar și când modul Cu prioritate este activat"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Fotografiile de profil apar pe ecranul de blocare"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Găsiți cu ușurință aceste conversații în baloane pe ecranul de pornire"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Întrerup modul Nu deranja"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Setări"</string>
@@ -1045,18 +1047,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Comutator"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butonul de accesibilitate a înlocuit gestul de accesibilitate\n\n"<annotation id="link">"Vedeți setările"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mutați butonul spre margine pentru a-l ascunde temporar"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mutați în stânga sus"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mutați în dreapta sus"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mutați în stânga jos"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mutați în dreapta jos"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mutați în afară și ascundeți"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mutați în afară și afișați"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Adăugați comenzi pentru dispozitivele conectate"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurați comenzile dispozitivelor"</string>
@@ -1136,35 +1132,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"În urmă cu mai puțin de <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"În urmă cu peste <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ziua de naștere"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> își serbează astăzi ziua de naștere"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Zi de naștere în curând"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"În curând <xliff:g id="NAME">%1$s</xliff:g> își va sărbători ziua de naștere"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Zi aniversară"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> își sărbătorește aniversarea"</string>
<string name="location_status" msgid="1294990572202541812">"Se afișează locația"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> își afișează locația"</string>
<string name="new_story_status" msgid="9012195158584846525">"Subiect nou"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> a trimis o poveste nouă"</string>
<string name="video_status" msgid="4548544654316843225">"Urmăresc"</string>
<string name="audio_status" msgid="4237055636967709208">"Se ascultă"</string>
<string name="game_status" msgid="1340694320630973259">"Se redă"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Prieteni"</string>
<string name="empty_status" msgid="5938893404951307749">"Conversăm prin chat diseară?"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Conținutul va apărea în curând"</string>
<string name="missed_call" msgid="4228016077700161689">"Apel nepreluat"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Vedeți mesaje recente, apeluri pierdute și actualizări de stare"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversație"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> a trimis un mesaj"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a trimis o imagine"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problemă la citirea măsurării bateriei"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Atingeți pentru mai multe informații"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nicio alarmă setată"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9557db3..9b29cc3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Увеличить площадь скриншота"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Закрыть скриншот"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Предварительный просмотр скриншота"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Верхняя граница"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Нижняя граница"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Запись видео с экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Способ ввода"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Геолокация"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Местоположение выкл."</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Заблокировать камеру"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Выключить микрофон"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ к камере"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ к микрофону"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступно"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Заблокировано"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Режим медиа"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Экстр. вызов"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запись экрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Начать"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Остановить"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Чтобы продолжить, предоставьте приложению <b><xliff:g id="APP">%s</xliff:g></b> доступ к микрофону устройства."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Чтобы продолжить, предоставьте приложению <b><xliff:g id="APP">%s</xliff:g></b> доступ к камере устройства."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблокировать микрофон устройства?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблокировать камеру устройства?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблокировать камеру и микрофон устройства?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование микрофона."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Будет снята блокировка доступа для всех приложений и сервисов с разрешением на использование камеры или микрофона."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Устройство"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Чтобы переключиться между приложениями, проведите по экрану вверх."</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Перетащите вправо, чтобы быстро переключиться между приложениями"</string>
@@ -503,7 +515,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Откл. фоновой передачи данных"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Отключить режим энергосбережения"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"Во время записи или трансляции у приложения \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" будет доступ ко всей информации, которая видна на экране или воспроизводится с устройства, в том числе к паролям, сведениям о платежах, фотографиям, сообщениям и прослушиваемым аудиозаписям."</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Во время записи или трансляции у сервиса, предоставляющего эту функцию, будет доступ ко всей информации, которая видна на экране или воспроизводится с устройства, в том числе к паролям, сведениям о платежах, фотографиям, сообщениям и прослушиваемым аудиозаписям."</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Во время записи или трансляции у сервиса, предоставляющего эту функцию, будет доступ ко всей информации, которая видна на экране или проигрывается на устройстве, включая пароли, сведения о платежах, фотографии, сообщения и воспроизводимые звуки."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Начать запись или трансляцию?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"Начать запись или трансляцию через приложение \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\"?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"Больше не показывать"</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Будильник"</string>
<string name="wallet_title" msgid="5369767670735827105">"Кошелек"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Можно использовать"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Добавить способ оплаты"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблокировать для использования"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Не удалось получить информацию о картах. Повторите попытку позже."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Рабочий профиль"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Режим полета"</string>
<string name="add_tile" msgid="6239678623873086686">"Добавить кнопку быстрого доступа"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> понижено до уровня \"Без звука\""</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Статус:</b> уровень важности повышен"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Статус:</b> уровень важности понижен"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Всегда показывается вверху списка уведомлений, даже если включен режим \"Только важные\""</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Важные разговоры"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Эту группу уведомлений нельзя настроить здесь."</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Чтобы обновить параметры навигации в системе, перейдите в настройки."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Разговор помечен как важный"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Важные разговоры."</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Эти разговоры показываются вверху списка, и вы можете их читать при включенном режиме \"Только важные\"."</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"На заблокированном экране показываются фото профиля."</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Эти разговоры можно найти во всплывающих чатах на главном экране."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Показывать в режиме \"Не беспокоить\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ОК"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Настройки"</string>
@@ -1050,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Чтобы временно скрыть кнопку, переместите ее к краю экрана"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перенести в левый верхний угол"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перенести в правый верхний угол"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Перенести в левый нижний угол"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Перенести в правый нижний угол"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перенести к краю и скрыть"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Вернуть из-за края и показать"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Управление устройствами"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавьте виджеты для управления устройствами."</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройте виджеты управления устройствами"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Прошло не более чем <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Прошло более чем <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"День рождения"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> празднует день рождения"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Скоро день рождения"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Скоро <xliff:g id="NAME">%1$s</xliff:g> празднует день рождения"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Годовщина"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> отмечает юбилей"</string>
<string name="location_status" msgid="1294990572202541812">"Доступ открыт"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> показывает свое местоположение"</string>
<string name="new_story_status" msgid="9012195158584846525">"Новая история"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> поделился новой историей"</string>
<string name="video_status" msgid="4548544654316843225">"Просмотр"</string>
<string name="audio_status" msgid="4237055636967709208">"Прослушивание аудио"</string>
<string name="game_status" msgid="1340694320630973259">"Игра запущена"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Друзья"</string>
<string name="empty_status" msgid="5938893404951307749">"Давайте поболтаем!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Контент скоро появится."</string>
<string name="missed_call" msgid="4228016077700161689">"Пропущенный вызов"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Просматривайте недавние сообщения, пропущенные звонки и обновления статуса."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Чат"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил сообщение"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил изображение"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удается получить данные об уровне заряда батареи"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Будильников нет"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 9f32ac5..2af8e39 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"තව ග්රහණය කරන්න"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"තිර රුව ඉවත ලන්න"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"තිර රූ පෙර දසුන"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ඉහළම මායිම"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"පහළම මායිම"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"තිර රෙකෝඩරය"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ආදාන ක්රමය"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ස්ථානය අක්රියයි"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"කැමරාව අවහිර කරන්න"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"මයික්රෆෝනය නිහඬ කරන්න"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"කැමරා ප්රවේශය"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"මයික් ප්රවේශය"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"තිබේ"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"අවහිර කර ඇත"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"මාධ්ය උපාංගය"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"හදිසි ඇමතුම් පමණි"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"තිර පටිගත කිරීම"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ආරම්භ කරන්න"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"නතර කරන්න"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"දිගටම කර ගෙන යාමට, <b><xliff:g id="APP">%s</xliff:g></b> හට ඔබගේ උපාංගයෙහි මයික්රෆෝනයට ප්රවේශය අවශ්යයි."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"දිගටම කර ගෙන යාමට, <b><xliff:g id="APP">%s</xliff:g></b> හට ඔබගේ උපාංගයෙහි කැමරාවට ප්රවේශය අවශ්යයි."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"උපාංග කැමරාව අවහිර කිරීම ඉවත් කරන්නද?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"උපාංග කැමරාව සහ මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"මෙය ඔබගේ මයික්රෆෝනය භාවිත කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"මෙය ඔබගේ කැමරාව භාවිතා කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"මෙය ඔබගේ කැමරාව හෝ මයික්රෆෝනය භාවිත කිරීමට ඉඩ දී ඇති සියලු යෙදුම් සහ සේවා සඳහා ප්රවේශය අවහිර කිරීම ඉවත් කරයි."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"උපාංගය"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"යෙදුම් මාරු කිරීමට ස්වයිප් කරන්න"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ඉක්මනින් යෙදුම් මාරු කිරීමට දකුණට අදින්න"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"එලාමය"</string>
<string name="wallet_title" msgid="5369767670735827105">"පසුම්බිය"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"සියල්ල පෙන්වන්න"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"ගෙවීමට අගුලු හරින්න"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"සූදානම්"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ගෙවීම පිහිටුවන්න"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"භාවිත කිරීමට අගුලු හරින්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ec2f637..152f291 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Nasnímať viac"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavrieť snímku obrazovky"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ukážka snímky obrazovky"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Horná hranica"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Dolná hranica"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metóda vstupu"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Poloha vypnutá"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokovať fotoaparát"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Vypnúť zvuk mikrofónu"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Prístup k fotoaparátu"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Prístup k mikrofónu"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"K dispozícii"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokované"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediálne zariadenie"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Len tiesňové volania"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Záznam obrazovky"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začať"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončiť"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Ak chcete pokračovať, <b><xliff:g id="APP">%s</xliff:g></b> požaduje prístup k mikrofónu zariadenia."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Ak chcete pokračovať, <b><xliff:g id="APP">%s</xliff:g></b> požaduje prístup k fotoaparátu zariadenia."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Chcete odblokovať mikrofón zariadenia?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Chcete odblokovať fotoaparát zariadenia?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Chcete odblokovať fotoaparát a mikrofón zariadenia?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať mikrofón."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať fotoaparát."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Táto akcia odblokuje prístup všetkým aplikáciám a službám, ktoré majú povolené používať fotoaparát alebo mikrofón."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Zariadenie"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Potiahnutím nahor prepnete aplikácie"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Presunutím doprava rýchlo prepnete aplikácie"</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Budík"</string>
<string name="wallet_title" msgid="5369767670735827105">"Peňaženka"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Pripravené"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Nastaviť platbu"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odomknúť a použiť"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Pri načítavaní kariet sa vyskytol problém. Skúste to neskôr."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Pracovný profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Režim v lietadle"</string>
<string name="add_tile" msgid="6239678623873086686">"Pridať dlaždicu"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Preradené nižšie do kategórie Tiché"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> Preradené vyššie"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Stav:</b> Preradené nižšie"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Vždy sa zobrazuje v hornej časti upozornení, aj keď je zapnutý režim priority"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavenia"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioritné konverzácie"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Túto skupinu upozornení nejde na tomto mieste konfigurovať"</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Prejdite do Nastavení a aktualizujte navigáciu v systéme"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Konverzácia je nastavená ako prioritná"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioritné konverzácie"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Tieto konverzácie sa zobrazujú na začiatku zoznamu a keď je zapnutý režim priority, vždy dostanete upozornenie"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profilové fotky sa zobrazujú na uzamknutej obrazovke"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Tieto konverzácie ľahko nájdete v bublinách na ploche"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Prerušovať režim bez vyrušení"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Dobre"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavenia"</string>
@@ -1050,18 +1052,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prepnúť"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tlačidlo dostupnosti nahradilo gesto dostupnosti\n\n"<annotation id="link">"Zobraziť nastavenia"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ak chcete tlačidlo dočasne skryť, presuňte ho k okraju"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Presunúť doľava nahor"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Presunúť doprava nahor"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Presunúť doľava nadol"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Presunúť doprava nadol"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Presunúť k okraju a skryť"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Presunúť z okraja a zobraziť"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte si ovládače pripojených zariadení"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládania zariadení"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Pred menej ako <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Pred viac ako <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Narodeniny"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> má narodeniny"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Blížia sa narodeniny"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> má čoskoro narodeniny"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Výročie"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> má výročie"</string>
<string name="location_status" msgid="1294990572202541812">"Zdieľa sa poloha"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> zdieľa polohu"</string>
<string name="new_story_status" msgid="9012195158584846525">"Nová správa"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> zdieľal(a) nový príbeh"</string>
<string name="video_status" msgid="4548544654316843225">"Pozerá sa video"</string>
<string name="audio_status" msgid="4237055636967709208">"Počúvam"</string>
<string name="game_status" msgid="1340694320630973259">"Hrá sa hra"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Priatelia"</string>
<string name="empty_status" msgid="5938893404951307749">"Porozprávajme sa."</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Obsah sa čoskoro zobrazí"</string>
<string name="missed_call" msgid="4228016077700161689">"Zmeškaný hovor"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pozrite si nedávne správy, zmeškané hovory a aktualizácie stavu"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzácia"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) správu"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) obrázok"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pri čítaní meradla batérie sa vyskytol problém"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím si zobrazíte ďalšie informácie"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Žiadny budík"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 868372c..1215f25 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Zajemi več"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Opusti posnetek zaslona"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Predogled posnetka zaslona"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Zgornji rob"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Spodnji rob"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Snemalnik zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Nenehno obveščanje o seji snemanja zaslona"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Način vnosa"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokacija izklopljena"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blokiranje fotoaparata"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Izklop mikrofona"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Dostop do fotoaparata"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Dostop do mikrofona"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Na voljo"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blokirano"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Predstavnostna naprava"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Le klici v sili"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snemanje zaslona"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začni"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ustavi"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Za nadaljevanje potrebuje aplikacija <b><xliff:g id="APP">%s</xliff:g></b> dostop do mikrofona v napravi."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Za nadaljevanje potrebuje aplikacija <b><xliff:g id="APP">%s</xliff:g></b> dostop do fotoaparata v napravi."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite odblokirati mikrofon v napravi?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite odblokirati fotoaparat v napravi?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite odblokirati fotoaparat in mikrofon v napravi?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo mikrofona."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo fotoaparata."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"S tem boste odblokirali dostop za vse aplikacije in storitve, ki imajo dovoljenje za uporabo fotoaparata ali mikrofona."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Naprava"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Za preklop aplikacij povlecite navzgor"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Povlecite v desno za hiter preklop med aplikacijami"</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Opozorilo"</string>
<string name="wallet_title" msgid="5369767670735827105">"Denarnica"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Pripravljeno"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Nastavite plačilno sredstvo"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odklenite za uporabo"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Pri pridobivanju kartic je prišlo do težave. Poskusite znova pozneje."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil za Android Work"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Način za letalo"</string>
<string name="add_tile" msgid="6239678623873086686">"Dodajanje ploščice"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stanje:</b> Uvrščeno med obvestila brez zvoka"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Stanje:</b> Uvrščeno višje"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Stanje:</b> Uvrščeno nižje"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Vedno prikazano na vrhu obvestil, tudi ko je vklopljen prednostni način"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavitve"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prednostni pogovori"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Te skupine obvestil ni mogoče konfigurirati tukaj"</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Če želite posodobiti krmarjenje po sistemu, odprite nastavitve"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Pogovor je nastavljen kot prednosten"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prednostni pogovori"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ti pogovori so prikazani na vrhu seznama in vas lahko vedno dosežejo, ko je vklopljen prednostni način."</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profilne slike so prikazane na zaklenjenem zaslonu."</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Te pogovore brez težav najdete v oblačkih na začetnem zaslonu."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Preglasi način »ne moti«"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"V redu"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavitve"</string>
@@ -1050,18 +1052,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Stikalo"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Gumb za funkcije za ljudi s posebnimi potrebami je zamenjal pripadajočo potezo.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Če želite gumb začasno skriti, ga premaknite ob rob."</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premakni zgoraj levo"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premakni zgoraj desno"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Premakni spodaj levo"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premakni spodaj desno"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premakni na rob in skrij"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premakni z roba in pokaži"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrolniki naprave"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrolnike za povezane naprave"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavitev kontrolnikov naprave"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Pred manj kot <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Pred več kot <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rojstni dan"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> ima rojstni dan."</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rojstni dan se bliža"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Oseba <xliff:g id="NAME">%1$s</xliff:g> bo kmalu imela rojstni dan."</string>
<string name="anniversary_status" msgid="1790034157507590838">"Obletnica"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> ima obletnico."</string>
<string name="location_status" msgid="1294990572202541812">"Deljenje lokacije"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> deli lokacijo."</string>
<string name="new_story_status" msgid="9012195158584846525">"Nova zgodba"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je delila novo zgodbo."</string>
<string name="video_status" msgid="4548544654316843225">"Gledanje"</string>
<string name="audio_status" msgid="4237055636967709208">"Poslušanje"</string>
<string name="game_status" msgid="1340694320630973259">"Igranje"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Prijatelji"</string>
<string name="empty_status" msgid="5938893404951307749">"Naj se klepet začne!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Vsebina bo kmalu prikazana."</string>
<string name="missed_call" msgid="4228016077700161689">"Neodgovorjeni klic"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Več kot <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Ogled nedavnih sporočil, neodgovorjenih klicev in posodobitev stanj"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Pogovor"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sporočilo."</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sliko."</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Težava z branjem indikatorja stanja napolnjenosti baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dotaknite se za več informacij"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ni nastavljenih alarmov"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 990aad9..433b49f 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Shkrep më shumë"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Hiq pamjen e ekranit"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pamja paraprake e imazhit"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Kufiri i sipërm"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Kufiri i poshtëm"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Regjistruesi i ekranit"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Regjistrimi i ekranit po përpunohet"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Njoftim i vazhdueshëm për një seancë regjistrimi të ekranit"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Metoda e hyrjes"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vendndodhja"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Vendndodhja është e çaktivizuar"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blloko kamerën"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Çaktivizo mikrofonin"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Qasja te kamera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Qasja te mikrofoni"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"E disponueshme"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"E bllokuar"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Pajisje e jashtme ruajtëse"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Vetëm telefonata urgjence"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Regjistrimi i ekranit"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Nis"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ndalo"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Për të vazhduar, <b><xliff:g id="APP">%s</xliff:g></b> ka nevojë të qaset në mikrofonin e pajisjes sate."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Për të vazhduar, <b><xliff:g id="APP">%s</xliff:g></b> ka nevojë të qaset në kamerën e pajisjes sate."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Të zhbllokohet mikrofoni i pajisjes?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Të zhbllokohet kamera e pajisjes?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Të zhbllokohen kamera dhe mikrofoni i pajisjes?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin mikrofonin tënd."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin kamerën tënde."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kjo zhbllokon qasjen për të gjitha aplikacionet dhe shërbimet që lejohen të përdorin kamerën ose mikrofonin tënd."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Pajisja"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Rrëshqit shpejt lart për të ndërruar aplikacionet"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Zvarrit djathtas për të ndërruar aplikacionet me shpejtësi"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Eternet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarmi"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Gati"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Konfiguro pagesën"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Shkyçe për ta përdorur"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Pati një problem me marrjen e kartave të tua. Provo përsëri më vonë"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profili i punës"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modaliteti i aeroplanit"</string>
<string name="add_tile" msgid="6239678623873086686">"Shto një pllakëz"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Statusi:</b> Ulur në nivel si në heshtje"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Statusi:</b> Renditur më lart"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Statusi:</b> Renditur më poshtë"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Shfaqen gjithmonë në krye të njoftimeve, edhe kur modaliteti \"Me përparësi\" është aktiv"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Bisedat me përparësi"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ky grup njoftimesh nuk mund të konfigurohet këtu"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Shko te \"Cilësimet\" për të përditësuar navigimin e sistemit"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Biseda u caktua me përparësi"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Bisedat me përparësi"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Këto biseda shfaqen në krye të listës sate dhe mund të të shfaqen gjithmonë kur modaliteti \"Me përparësi\" është aktiv"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Fotografitë e profilit shfaqen në ekranin e kyçjes"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Mund t\'i gjesh me lehtësi këto biseda te flluskat në ekranin bazë"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ndërprit \"Mos shqetëso\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"E kuptova"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Cilësimet"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Ndërro"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butoni i qasshmërisë është zëvendësuar me gjestin e qasshmërisë\n\n"<annotation id="link">"Shiko cilësimet"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Zhvendose butonin në skaj për ta fshehur përkohësisht"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Zhvendos lart majtas"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Zhvendos lart djathtas"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Zhvendos poshtë majtas"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Zhvendos poshtë djathtas"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Zhvendose te skaji dhe fshihe"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Zhvendose jashtë skajit dhe shfaqe"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrollet e pajisjes"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Shto kontrolle për pajisjet e tua të lidhura"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguro kontrollet e pajisjes"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Më pak se <xliff:g id="DURATION">%1$s</xliff:g> më parë"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Mbi <xliff:g id="DURATION">%1$s</xliff:g> më parë"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ditëlindja"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> ka ditëlindjen"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Ditëlindje së shpejti"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> ka ditëlindjen së shpejti"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Përvjetor"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> ka përvjetorin"</string>
<string name="location_status" msgid="1294990572202541812">"Ndarja e vendndodhjes"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> po ndan vendndodhjen"</string>
<string name="new_story_status" msgid="9012195158584846525">"Histori e re"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ndau një histori të re"</string>
<string name="video_status" msgid="4548544654316843225">"Po shikon"</string>
<string name="audio_status" msgid="4237055636967709208">"Po dëgjon"</string>
<string name="game_status" msgid="1340694320630973259">"Po luhet"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Miq"</string>
<string name="empty_status" msgid="5938893404951307749">"Le të bisedojmë sonte!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Përmbajtjet do të shfaqen së shpejti"</string>
<string name="missed_call" msgid="4228016077700161689">"Telefonatë e humbur"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Mbi <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Shiko mesazhet e fundit, telefonatat e humbura dhe përditësimet e statusit"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Biseda"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një mesazh"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një imazh"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem me leximin e matësit të baterisë"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trokit për më shumë informacione"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nuk është caktuar asnjë alarm"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 55d75f8..54151e4 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Снимите још"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Одбаците снимак екрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед снимка екрана"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Горња граница"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Доња граница"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
@@ -123,7 +129,7 @@
<string name="usb_preference_title" msgid="1439924437558480718">"Опције USB преноса датотека"</string>
<string name="use_mtp_button_title" msgid="5036082897886518086">"Прикључи као медија плејер (MTP)"</string>
<string name="use_ptp_button_title" msgid="7676427598943446826">"Прикључи као камеру (PTP)"</string>
- <string name="installer_cd_button_title" msgid="5499998592841984743">"Инсталирај Android пребацивање датотека за Mac"</string>
+ <string name="installer_cd_button_title" msgid="5499998592841984743">"Инсталирај Android пребацивање фајлова за Mac"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Назад"</string>
<string name="accessibility_home" msgid="5430449841237966217">"Почетна"</string>
<string name="accessibility_menu" msgid="2701163794470513040">"Мени"</string>
@@ -350,8 +356,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод уноса"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Локација је искључена"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Блокирај камеру"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Искључи микрофон"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Приступ камери"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Приступ микрофону"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Доступно"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Блокирано"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медијски уређај"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Само хитни позиви"</string>
@@ -424,8 +432,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Снимак екрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почните"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зауставите"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"<b><xliff:g id="APP">%s</xliff:g></b> захтева приступ микрофону уређаја ради настављања."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"<b><xliff:g id="APP">%s</xliff:g></b> захтева приступ камери уређаја ради настављања."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Желите да одблокирате микрофон уређаја?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Желите да одблокирате камеру уређаја?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Желите да одблокирате камеру и микрофон уређаја?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење микрофона."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење камере."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Овим ће се одблокирати приступ за све апликације и услуге које имају дозволу за коришћење камере или микрофона."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Уређај"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Превуците нагоре да бисте мењали апликације"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Превуците удесно да бисте брзо променили апликације"</string>
@@ -660,18 +672,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Етернет"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Аларм"</string>
<string name="wallet_title" msgid="5369767670735827105">"Новчаник"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Спремно"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Подесите плаћање"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Откључај ради коришћења"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Дошло је до проблема при преузимању картица. Пробајте поново касније"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Пословни профил"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Режим рада у авиону"</string>
<string name="add_tile" msgid="6239678623873086686">"Додај плочицу"</string>
@@ -740,11 +748,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> Деградирано у Нечујно"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Статус:</b> Рангирано више"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Статус:</b> Рангирано ниже"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Увек се приказује у врху обавештења чак и када је Приоритетни режим укључен"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Подешавања"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Приоритетне конверзације"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ова група обавештења не може да се конфигурише овде"</string>
@@ -1020,14 +1026,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Идите у Подешавања да бисте ажурирали навигацију система"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Конверзација је подешена на приоритетну"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Приоритетне конверзације"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ове конверзације се приказују у врху листе и увек могу да допру до вас када је Приоритетни режим укључен"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Слике профила се приказују на закључаном екрану"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Лако можете да пронађете ове конверзације у облачићима на почетном екрану"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Омета подешавање Не узнемиравај"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Важи"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Подешавања"</string>
@@ -1045,18 +1047,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Померите дугме до ивице да бисте га привремено сакрили"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Премести горе лево"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Премести горе десно"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Премести доле лево"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Премести доле десно"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до ивице и сакриј"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести изван ивице и прикажи"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроле за повезане уређаје"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Подесите контроле уређаја"</string>
@@ -1136,35 +1132,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Пре мање од <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Пре више од <xliff:g id="DURATION">%1$s</xliff:g>"</string>
<string name="birthday_status" msgid="2596961629465396761">"Рођендан"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> данас слави рођендан"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Рођендан је ускоро"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> ускоро слави рођендан"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Годишњица"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> данас слави годишњицу"</string>
<string name="location_status" msgid="1294990572202541812">"Дели се локација"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> дели локацију"</string>
<string name="new_story_status" msgid="9012195158584846525">"Нова прича"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> дели нову причу"</string>
<string name="video_status" msgid="4548544654316843225">"Гледа се"</string>
<string name="audio_status" msgid="4237055636967709208">"Слуша се"</string>
<string name="game_status" msgid="1340694320630973259">"Игра се"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Пријатељи"</string>
<string name="empty_status" msgid="5938893404951307749">"Ћаскамо вечерас!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Садржај ће се ускоро појавити"</string>
<string name="missed_call" msgid="4228016077700161689">"Пропуштен позив"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Погледајте недавне поруке, пропуштене позиве и ажурирања статуса"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Конверзација"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> шаље поруку"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> шаље слику"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем са очитавањем мерача батерије"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Додирните за више информација"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Аларм није подешен"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8284cbd..ff12781 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Fånga mer"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Stäng skärmbild"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Förhandsgranskning av skärmbild"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Övre gräns"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Nedre gräns"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Skärminspelare"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandlar skärminspelning"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Avisering om att skärminspelning pågår"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Inmatningsmetod"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Plats"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Plats har inaktiverats"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Blockera Kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Stäng av mikrofonen"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraåtkomst"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonåtkomst"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Tillgänglig"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Blockerad"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medieenhet"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Endast nödsamtal"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skärminspelning"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starta"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppa"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"<b><xliff:g id="APP">%s</xliff:g></b> behöver behörighet till enhetens mikrofon för att fortsätta."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"<b><xliff:g id="APP">%s</xliff:g></b> behöver behörighet till enhetens kamera för att fortsätta."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vill du återaktivera enhetens mikrofon?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vill du återaktivera enhetens kamera?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vill du återaktivera enhetens kamera och mikrofon?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda mikrofonen."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda kameran."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Detta återaktiverar åtkomsten för alla appar och tjänster som tillåts att använda kameran eller mikrofonen."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Enhet"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Byt appar genom att svepa uppåt"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Tryck och dra åt höger för att snabbt byta mellan appar"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Klar"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Konfigurera betalning"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås upp för att använda"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Det gick inte att hämta dina kort. Försök igen senare."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Jobbprofil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flygplansläge"</string>
<string name="add_tile" msgid="6239678623873086686">"Lägg till en ruta"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Ändrad till Tyst"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Status:</b> Höjd"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Status:</b> Sänkt"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Visas alltid överst i aviseringarna, även när prioritetsläget är på"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Inställningar"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Prioriterade konversationer"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Den här aviseringsgruppen kan inte konfigureras här"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Öppna inställningarna och uppdatera systemnavigeringen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Konversationen har angetts som prioriterad"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Prioriterade konversationer"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"De här konversationerna visas överst i listan och kan alltid nå dig när prioritetsläget på"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profilbilder visas på låsskärmen"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Du hittar enkelt de här konversationerna i bubblor på startskärmen"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Avbryt Stör ej"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Inställningar"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Reglage"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tillgänglighetsknappen har ersatt tillgänglighetsrörelsen\n\n"<annotation id="link">"Visa inställningarna"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytta knappen till kanten för att dölja den tillfälligt"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytta högst upp till vänster"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytta högst upp till höger"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Flytta längst ned till vänster"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flytta längst ned till höger"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytta till kanten och dölj"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytta från kanten och visa"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyrning"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Lägg till snabbkontroller för anslutna enheter"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurera enhetsstyrning"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Mindre än <xliff:g id="DURATION">%1$s</xliff:g> sedan"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Mer än <xliff:g id="DURATION">%1$s</xliff:g> sedan"</string>
<string name="birthday_status" msgid="2596961629465396761">"Födelsedag"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> fyller år"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Födelsedag inom kort"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> fyller snart år"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Högtidsdag"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> har bemärkelsedag"</string>
<string name="location_status" msgid="1294990572202541812">"Delar plats"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> delar sin plats"</string>
<string name="new_story_status" msgid="9012195158584846525">"Ny artikel"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> delade en ny story"</string>
<string name="video_status" msgid="4548544654316843225">"Tittar"</string>
<string name="audio_status" msgid="4237055636967709208">"Lyssnar"</string>
<string name="game_status" msgid="1340694320630973259">"Spelar"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Vänner"</string>
<string name="empty_status" msgid="5938893404951307749">"Vi chattar i kväll!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Innehåll visas snart"</string>
<string name="missed_call" msgid="4228016077700161689">"Missat samtal"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"över <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Se de senaste meddelandena, missade samtal och statusuppdateringar"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konversation"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> skickade ett meddelande"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> skickade en bild"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batteriindikatorn visas inte"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryck för mer information"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Inget inställt alarm"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 848d5b5..1b98698 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Nasa zaidi"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ondoa picha ya skrini"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Onyesho la kukagua picha ya skrini"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Mpaka wa sehemu ya juu"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Mpaka wa sehemu ya chini"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Kinasa Skrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Mbinu ya uingizaji"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Kutambua Mahali"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Kitambua eneo kimezimwa"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Zuia Kamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Zima Maikrofoni"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Ufikiaji wa kamera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Ufikiaji wa maikrofoni"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Unapatikana"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Umezuiwa"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Kifaa cha faili"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Simu za Dharura Pekee"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rekodi ya Skrini"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Anza kurekodi"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Acha kurekodi"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Ili uendelee, <b><xliff:g id="APP">%s</xliff:g></b> inahitaji ruhusa ya kufikia maikrofoni ya kifaa chako."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Ili uendelee, <b><xliff:g id="APP">%s</xliff:g></b> inahitaji ruhusa ya kufikia kamera ya kifaa chako."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Ungependa kuondoa kizuizi kwenye maikrofoni ya kifaa?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Ungependa kuondoa kizuizi kwenye kamera ya kifaa?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Ungependa kuondoa kizuizi kwenye kamera na maikrofoni ya kifaa?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Hatua hii huondoa kizuizi cha kufikia kwa programu na huduma zote zinazoruhusiwa kutumia maikrofoni yako."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Hatua hii huondoa kizuizi cha kufikia kwa programu na huduma zote zinazoruhusiwa kutumia kamera yako."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Hatua hii huondoa kizuizi cha kufikia kwa programu na huduma zote zinazoruhusiwa kutumia kamera au maikrofoni yako."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Kifaa"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Telezesha kidole juu ili ubadilishe programu"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Buruta kulia ili ubadilishe programu haraka"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethaneti"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Kengele"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Onyesha zote"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Fungua ili ulipe"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Tayari"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Weka njia ya kulipa"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Fungua ili utumie"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index a6321fe..e2b2e25 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -15,8 +15,6 @@
~ limitations under the License
-->
<resources>
- <integer name="quick_settings_num_columns">3</integer>
-
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index 302e5e4..0000000
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2012, 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>
- <dimen name="keyguard_clock_notifications_margin">36dp</dimen>
-
- <dimen name="keyguard_indication_margin_bottom">80dp</dimen>
-
- <!-- Screen pinning request width (just a little bit bigger than the three buttons here -->
- <dimen name="screen_pinning_request_width">490dp</dimen>
- <!-- Screen pinning request bottom button circle widths -->
- <dimen name="screen_pinning_request_button_width">162dp</dimen>
- <!-- Screen pinning request, controls padding on bigger screens, bigger nav bar -->
- <dimen name="screen_pinning_request_frame_padding">39dp</dimen>
- <!-- Screen pinning request side views to match nav bar
- In sw600dp we want the buttons centered so this fills the space,
- (screen_pinning_request_width - 3 * screen_pinning_request_button_width) / 2 -->
- <dimen name="screen_pinning_request_side_width">2dp</dimen>
-
- <dimen name="navigation_key_width">162dp</dimen>
- <dimen name="navigation_key_padding">42dp</dimen>
-
- <dimen name="battery_detail_graph_space_top">27dp</dimen>
- <dimen name="battery_detail_graph_space_bottom">27dp</dimen>
-
- <dimen name="qs_tile_margin_top">32dp</dimen>
- <dimen name="qs_brightness_padding_top">6dp</dimen>
- <dimen name="qs_detail_margin_top">28dp</dimen>
-
- <!-- In split shade mode notifications should be aligned to QS header so the value should be
- adjusted to qs header height and height of centered content inside of it:
- (quick_qs_offset_height (48dp) - ongoing_appops_chip_height (24dp) ) / 2 -->
- <dimen name="notifications_top_padding_split_shade">12dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index d6e1b69..e4117b9 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"கூடுதலாகப் படமெடு"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ஸ்கிரீன்ஷாட்டை நிராகரிக்கும்"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ஸ்கிரீன்ஷாட்டின் மாதிரிக்காட்சி"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"மேற்புற எல்லை"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"கீழ்ப்புற எல்லை"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"ஸ்கிரீன் ரெக்கார்டர்"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"உள்ளீட்டு முறை"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"இருப்பிடம்"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"இருப்பிடத்தை முடக்கு"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"கேமராவைத் தடு"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"மைக்ரோஃபோனை ஒலியடக்கு"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"கேமரா அணுகல்"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"மைக் அணுகல்"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"கிடைக்கிறது"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"தடைசெய்யப்பட்டது"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"மீடியா சாதனம்"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"அவசரகால அழைப்புகள் மட்டும்"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ஸ்கிரீன் ரெக்கார்டு"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"தொடங்கு"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"நிறுத்து"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"தொடர, உங்கள் சாதனத்தின் மைக்ரோஃபோனை அணுகுவதற்கு <b><xliff:g id="APP">%s</xliff:g></b> ஆப்ஸுக்கு அனுமதி வேண்டும்."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"தொடர, உங்கள் சாதனத்தின் கேமராவை அணுகுவதற்கு <b><xliff:g id="APP">%s</xliff:g></b> ஆப்ஸுக்கு அனுமதி வேண்டும்."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"சாதனத்தின் மைக்ரோஃபோனுக்கான தடுப்பை நீக்கவா?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"சாதனத்தின் கேமராவுக்கான தடுப்பை நீக்கவா?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"சாதனத்தின் கேமராவுக்கும் மைக்ரோஃபோனுக்குமான தடுப்பை நீக்கவா?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"உங்கள் மைக்ரோஃபோனைப் பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"உங்கள் கேமராவைப் பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"உங்கள் கேமராவையோ மைக்ரோஃபோனையோ பயன்படுத்த அனுமதிக்கப்பட்டுள்ள அனைத்து ஆப்ஸ் மற்றும் சேவைகளை அணுகுவதற்கான தடுப்பை இது நீக்கும்."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"சாதனம்"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, மேல்நோக்கி ஸ்வைப் செய்க"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ஆப்ஸை வேகமாக மாற்ற, வலப்புறம் இழுக்கவும்"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ஈதர்நெட்"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"அலாரம்"</string>
<string name="wallet_title" msgid="5369767670735827105">"வாலட்"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"தயார்"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"பேமெண்ட் முறையை அமையுங்கள்"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"பயன்படுத்துவதற்கு அன்லாக் செய்க"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"உங்கள் கார்டுகளின் விவரங்களைப் பெறுவதில் சிக்கல் ஏற்பட்டது, பிறகு முயலவும்"</string>
<string name="status_bar_work" msgid="5238641949837091056">"பணிக் கணக்கு"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"விமானப் பயன்முறை"</string>
<string name="add_tile" msgid="6239678623873086686">"டைலைச் சேர்க்கும்"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>நிலை:</b> நிசப்த நிலைக்குக் குறைத்து அமைக்கப்பட்டது"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>நிலை:</b> முக்கியத்துவம் உயர்த்தப்பட்டது"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>நிலை:</b> முக்கியத்துவம் குறைக்கப்பட்டது"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"முன்னுரிமைப் பயன்முறை இயக்கப்பட்டிருக்கும்போதும், எப்போதுமே அறிவிப்புகளின் மேல்புறத்தில் காட்டப்படும்"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"அமைப்புகள்"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"முன்னுரிமை உரையாடல்கள்"</string>
<string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"சிஸ்டம் நேவிகேஷனை மாற்ற ’அமைப்புகளுக்குச்’ செல்லவும்"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"முன்னுரிமை அளிக்கப்பட்ட உரையாடலாக அமைக்கப்பட்டது"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"முன்னுரிமை உரையாடல்கள்"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"முன்னுரிமைப் பயன்முறை இயக்கப்பட்டிருக்கும்போது பட்டியலின் மேல்புறத்தில் இந்த உரையாடல்கள் எப்போதுமே காட்டப்படும்"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"பூட்டுத் திரையில் சுயவிவரப் படங்கள் காட்டப்படும்"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"முகப்புத் திரையில் தோன்றும் குமிழ்களில் இந்த உரையாடல்களை எளிதாகப் பார்க்கலாம்"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தைக் குறுக்கிடும்"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"சரி"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"அமைப்புகள்"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"பட்டனைத் தற்காலிகமாக மறைக்க ஓரத்திற்கு நகர்த்தும்"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"மேலே இடதுபுறத்திற்கு நகர்த்து"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"மேலே வலதுபுறத்திற்கு நகர்த்து"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"கீழே இடதுபுறத்திற்கு நகர்த்து"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"கீழே வலதுபுறத்திற்கு நகர்த்து"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ஓரத்திற்கு நகர்த்தி மறை"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ஓரத்திற்கு நகர்த்தி, காட்டு"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"இணைக்கப்பட்ட சாதனங்களில் கட்டுப்பாடுகளைச் சேர்க்கலாம்"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"சாதனக் கட்டுப்பாடுகளை அமைத்தல்"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>க்குக் குறைவாக"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>க்கு முன்பு"</string>
<string name="birthday_status" msgid="2596961629465396761">"பிறந்தநாள்"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> அவர்களின் பிறந்தநாள்"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"விரைவில் பிறந்தநாள்"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> அவர்களின் பிறந்தநாள் விரைவில் வரவுள்ளது"</string>
<string name="anniversary_status" msgid="1790034157507590838">"ஆண்டு விழா"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> அவர்களின் ஆண்டுவிழா"</string>
<string name="location_status" msgid="1294990572202541812">"இடத்தைப் பகிர்கிறது"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> இருப்பிடத்தைப் பகிர்கிறார்"</string>
<string name="new_story_status" msgid="9012195158584846525">"புதிய செய்தி"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> புதிய கதையைப் பகிர்ந்துள்ளார்"</string>
<string name="video_status" msgid="4548544654316843225">"பார்க்கிறீர்கள்"</string>
<string name="audio_status" msgid="4237055636967709208">"ஆடியோ கேட்கிறீர்கள்"</string>
<string name="game_status" msgid="1340694320630973259">"விளையாடுகிறீர்கள்"</string>
<string name="empty_user_name" msgid="3389155775773578300">"நண்பர்கள்"</string>
<string name="empty_status" msgid="5938893404951307749">"இன்றிரவு உரையாடலாம்!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"உள்ளடக்கம் விரைவில் தோன்றும்"</string>
<string name="missed_call" msgid="4228016077700161689">"தவறிய அழைப்பு"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"சமீபத்திய மெசேஜ்களையும் தவறிய அழைப்புகளையும் ஸ்டேட்டஸ் அப்டேட்களையும் பார்க்கலாம்"</string>
<string name="people_tile_title" msgid="6589377493334871272">"உரையாடல்"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு மெசேஜ் அனுப்பியுள்ளார்"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு படம் அனுப்பியுள்ளார்"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"பேட்டரி அளவை அறிவதில் சிக்கல்"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"மேலும் தகவல்களுக்கு தட்டவும்"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"அலாரம் எதுவுமில்லை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 8b2392e..1041f64 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"మరిన్ని క్యాప్చర్ చేయండి"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"స్క్రీన్షాట్ను విస్మరించు"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"స్క్రీన్షాట్ ప్రివ్యూ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ఎగువ సరిహద్దు"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"దిగువ సరిహద్దు"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"స్క్రీన్ రికార్డర్"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్గోయింగ్ నోటిఫికేషన్"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ఇన్పుట్ పద్ధతి"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"లొకేషన్"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"లొకేషన్ ఆఫ్లో ఉంది"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"కెమెరాను బ్లాక్ చేయి"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"మైక్రోఫోన్ను మ్యూట్ చేయి"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ప్రసార మాధ్యమ పరికరం"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ఎమర్జెన్సీ కాల్స్ మాత్రమే"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"స్క్రీన్ రికార్డ్"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించు"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ఆపు"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"కొనసాగించడానికి, <b><xliff:g id="APP">%s</xliff:g></b>కు మీ పరికరం యొక్క మైక్రోఫోన్ యాక్సెస్ అవసరం."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"కొనసాగించడానికి, <b><xliff:g id="APP">%s</xliff:g></b&gtకు మీ పరికరం యొక్క కెమెరా యాక్సెస్ అవసరం."</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"పరికరం"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"యాప్లను మార్చడం కోసం ఎగువకు స్వైప్ చేయండి"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"యాప్లను శీఘ్రంగా స్విచ్ చేయడానికి కుడి వైపుకు లాగండి"</string>
@@ -497,7 +519,7 @@
<string name="battery_saver_notification_text" msgid="2617841636449016951">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"బ్యాటరీ సేవర్ను ఆఫ్ చేయండి"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్వర్డ్లు, చెల్లింపు వివరాలు, ఫోటోలు, సందేశాలు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్ను అందిస్తున్న సర్వీసు యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, చెల్లింపు వివరాలు, ఫోటోలు, సందేశాలు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్ను అందిస్తున్న సర్వీసు యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>తో రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"మళ్లీ చూపవద్దు"</string>
@@ -657,9 +679,9 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ఈథర్నెట్"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"అలారం"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
<!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
<skip />
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index b8e586d..30723fa 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"จับภาพได้มากขึ้น"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ปิดภาพหน้าจอ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ตัวอย่างภาพหน้าจอ"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"ขอบเขตด้านบน"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ขอบเขตด้านล่าง"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมบันทึกหน้าจอ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"วิธีป้อนข้อมูล"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ตำแหน่ง"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ปิดตำแหน่ง"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"บล็อกกล้องถ่ายรูป"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"ปิดเสียงไมโครโฟน"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"สิทธิ์เข้าถึงกล้อง"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"สิทธิ์เข้าถึงไมโครโฟน"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"มี"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ถูกบล็อก"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"อุปกรณ์สื่อ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"โทรฉุกเฉินเท่านั้น"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"บันทึกหน้าจอ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"เริ่ม"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"หยุด"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"<b><xliff:g id="APP">%s</xliff:g></b> ต้องได้รับสิทธิ์เข้าถึงไมโครโฟนของอุปกรณ์เพื่อดำเนินการต่อ"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"<b><xliff:g id="APP">%s</xliff:g></b> ต้องได้รับสิทธิ์เข้าถึงกล้องของอุปกรณ์เพื่อดำเนินการต่อ"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"เลิกบล็อกไมโครโฟนของอุปกรณ์ใช่ไหม"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"เลิกบล็อกกล้องของอุปกรณ์ใช่ไหม"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"เลิกบล็อกกล้องและไมโครโฟนของอุปกรณ์ใช่ไหม"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้ไมโครโฟนของคุณ"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้กล้องของคุณ"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"การดำเนินการนี้จะเลิกบล็อกสิทธิ์เข้าถึงของแอปและบริการทั้งหมดที่ได้รับอนุญาตให้ใช้กล้องหรือไมโครโฟนของคุณ"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"อุปกรณ์"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"เลื่อนขึ้นเพื่อสลับแอป"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"ลากไปทางขวาเพื่อสลับแอปอย่างรวดเร็ว"</string>
@@ -550,8 +562,8 @@
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"องค์กรของคุณติดตั้งผู้ออกใบรับรองในอุปกรณ์นี้ อาจมีการตรวจสอบหรือแก้ไขการจราจรของข้อมูลในเครือข่ายที่ปลอดภัยของคุณ"</string>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"องค์กรของคุณติดตั้งผู้ออกใบรับรองในโปรไฟล์งาน อาจมีการตรวจสอบหรือแก้ไขการจราจรของข้อมูลในเครือข่ายที่ปลอดภัยของคุณ"</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"มีการติดตั้งผู้ออกใบรับรองในอุปกรณ์นี้ อาจมีการตรวจสอบหรือแก้ไขการจราจรของข้อมูลในเครือข่ายที่ปลอดภัยของคุณ"</string>
- <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"ผู้ดูแลระบบได้เปิดการบันทึกเครือข่าย ซึ่งจะตรวจสอบการจราจรของข้อมูลในอุปกรณ์ของคุณ"</string>
- <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"ผู้ดูแลระบบได้เปิดการบันทึกเครือข่าย ซึ่งจะตรวจสอบการรับส่งข้อมูลในโปรไฟล์งาน แต่ไม่ตรวจสอบในโปรไฟล์ส่วนตัวของคุณ"</string>
+ <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"ผู้ดูแลระบบได้เปิดการบันทึกกิจกรรมของเครือข่าย ซึ่งจะตรวจสอบการรับส่งข้อมูลในอุปกรณ์ของคุณ"</string>
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"ผู้ดูแลระบบได้เปิดการบันทึกกิจกรรมของเครือข่าย ซึ่งจะตรวจสอบการรับส่งข้อมูลในโปรไฟล์งานแต่ไม่ตรวจสอบในโปรไฟล์ส่วนตัวของคุณ"</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"คุณเชื่อมต่ออยู่กับ <xliff:g id="VPN_APP">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์"</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"คุณเชื่อมต่ออยู่กับ <xliff:g id="VPN_APP_0">%1$s</xliff:g> และ <xliff:g id="VPN_APP_1">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์"</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"โปรไฟล์งานของคุณเชื่อมต่ออยู่กับ <xliff:g id="VPN_APP">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์"</string>
@@ -566,7 +578,7 @@
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"เปิดการตั้งค่า VPN"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"เปิดข้อมูลรับรองที่เชื่อถือได้"</string>
- <string name="monitoring_description_network_logging" msgid="577305979174002252">"ผู้ดูแลระบบได้เปิดการทำบันทึกเครือข่าย ซึ่งจะติดตามดูการรับส่งข้อมูลบนอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบสำหรับข้อมูลเพิ่มเติม"</string>
+ <string name="monitoring_description_network_logging" msgid="577305979174002252">"ผู้ดูแลระบบได้เปิดการบันทึกกิจกรรมของเครือข่าย ซึ่งจะตรวจสอบการรับส่งข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบหากต้องการข้อมูลเพิ่มเติม"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"คุณได้ให้สิทธิ์แอปในการตั้งค่าการเชื่อมต่อ VPN\n\nแอปนี้จะสามารถตรวจสอบอุปกรณ์และกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"โปรไฟล์งานของคุณได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nผู้ดูแลระบบสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ ซึ่งรวมถึงอีเมล แอป และเว็บไซต์ต่างๆ\n\nโปรดติดต่อผู้ดูแลระบบสำหรับข้อมูลเพิ่มเติม\n\nนอกจากนี้คุณยังเชื่อมต่อกับ VPN ซึ่งตรวจสอบกิจกรรมในเครือข่ายของคุณได้"</string>
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"อุปกรณ์นี้จัดการโดยผู้ปกครอง ผู้ปกครองจะดูและจัดการข้อมูลต่างๆ ได้ เช่น แอปที่คุณใช้ ตำแหน่งของคุณ และเวลาอยู่หน้าจอ"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"อีเทอร์เน็ต"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"การปลุก"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"แสดงทั้งหมด"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"ปลดล็อกเพื่อชำระเงิน"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"พร้อม"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ตั้งค่าการชำระเงิน"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ปลดล็อกเพื่อใช้"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9d3378a..7b6c07e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Mag-capture pa"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"I-dismiss ang screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Preview ng screenshot"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Pinakamataas na limitasyon"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Pinakamababang limitasyon"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder ng Screen"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pinoproseso screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Kasalukuyang notification para sa session ng pag-record ng screen"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Pamamaraan ng Pag-input"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasyon"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Naka-off ang Lokasyon"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"I-block ang Camera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"I-mute ang Mikropono"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Access sa camera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Access sa mikropono"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Available"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Naka-block"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Device ng media"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Mga Pang-emergency na Tawag Lamang"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Pag-record ng Screen"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Magsimula"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ihinto"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Para magpatuloy, kailangan ng <b><xliff:g id="APP">%s</xliff:g></b> ng access sa mikropono ng iyong device."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Para magpatuloy, kailangan ng <b><xliff:g id="APP">%s</xliff:g></b> ng access sa camera ng iyong device."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"I-unblock ang mikropono ng device?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"I-unblock ang camera ng device?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"I-unblock ang camera at mikropono ng device?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong mikropono."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong camera."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ina-unblock nito ang access para sa lahat ng app at serbisyong pinapayagang gumamit ng iyong camera o mikropono."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Device"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Mag-swipe pataas upang lumipat ng app"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"I-drag pakanan para mabilisang magpalipat-lipat ng app"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Ipakita lahat"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"I-unlock para magbayad"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Handa na"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Mag-set up ng pagbabayad"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"I-unlock para magamit"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 44ed1ae..6bbb41f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Daha fazla ekran görüntüsü al"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran görüntüsünü kapat"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran görüntüsü önizlemesi"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Üst sınır"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Alt sınır"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Giriş Yöntemi"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Konum"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Konum Bilgisi Kapalı"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Kamerayı Engelle"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mikrofonun Sesini Kapat"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kamera erişimi"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofon erişimi"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Kullanılabilir"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Engellendi"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medya cihazı"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Yalnızca Acil Çağrılar İçin"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekran Kaydı"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlat"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Durdur"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Devam etmek için <b><xliff:g id="APP">%s</xliff:g></b> uygulamasının cihazınızın mikrofonuna erişmesi gerekiyor."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Devam etmek için <b><xliff:g id="APP">%s</xliff:g></b> uygulamasının cihazınızın kamerasına erişmesi gerekiyor."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonunun engellemesi kaldırılsın mı?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerasının engellemesi kaldırılsın mı?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası ile mikrofonunun engellemesi kaldırılsın mı?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Bu işlem, mikrofonunuzu kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Bu işlem, kameranızı kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Bu işlem, kamera veya mikrofonunuzu kullanmasına izin verilen tüm uygulama ve hizmetlere erişimin engellemesini kaldırır."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Cihaz"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Uygulamalar arasında geçiş yapmak için yukarı kaydırın"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Uygulamaları hızlıca değiştirmek için sağa kaydırın"</string>
@@ -621,7 +633,7 @@
<string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string>
<string name="stream_dtmf" msgid="7322536356554673067">"Çift ton çoklu frekans"</string>
<string name="stream_accessibility" msgid="3873610336741987152">"Erişilebilirlik"</string>
- <string name="ring_toggle_title" msgid="5973120187287633224">"Çağrılar"</string>
+ <string name="ring_toggle_title" msgid="5973120187287633224">"Aramalar"</string>
<string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zili çaldır"</string>
<string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Titreşim"</string>
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"Sesi kapat"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Alarm"</string>
<string name="wallet_title" msgid="5369767670735827105">"Cüzdan"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Tümünü göster"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Ödeme için kilidi aç"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Hazır"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Ödeme ayarlarını belirle"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Kullanmak için kilidi aç"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 6a762d7..3995e56 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Включити більше деталей"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Закрити знімок екрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Перегляд знімка екрана"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Верхня межа"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Нижня межа"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Відеозапис екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
@@ -351,8 +357,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод введення"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Місцезнаходження"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Місцезнаходження вимкнено"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Заблокувати камеру"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Вимкнути мікрофон"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ до камери"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ до мікрофона"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Дозволено"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Заблоковано"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Носій"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Екстрені виклики"</string>
@@ -426,8 +434,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запис екрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почати"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зупинити"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Щоб продовжити, надайте додатку <b><xliff:g id="APP">%s</xliff:g></b> доступ до мікрофона пристрою."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Щоб продовжити, надайте додатку <b><xliff:g id="APP">%s</xliff:g></b> доступ до камери пристрою."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Надати доступ до мікрофона?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Надати доступ до камери пристрою?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Надати доступ до камери й мікрофона?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Усі додатки та сервіси, які можуть користуватися вашим мікрофоном, отримають доступ."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Усі додатки та сервіси, які можуть користуватися вашою камерою, отримають доступ."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Усі додатки та сервіси, які можуть користуватися вашою камерою чи мікрофоном, отримають доступ."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Пристрій"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Проводьте пальцем угору, щоб переходити між додатками"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Перетягуйте праворуч, щоб швидко переходити між додатками"</string>
@@ -544,7 +556,7 @@
<string name="monitoring_title_profile_owned" msgid="6301118649405449568">"Відстеження профілю"</string>
<string name="monitoring_title" msgid="4063890083735924568">"Відстеження дій у мережі"</string>
<string name="monitoring_subtitle_vpn" msgid="800485258004629079">"Мережа VPN"</string>
- <string name="monitoring_subtitle_network_logging" msgid="2444199331891219596">"Реєстрація в мережі"</string>
+ <string name="monitoring_subtitle_network_logging" msgid="2444199331891219596">"Журнал мережі"</string>
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"Сертифікати центру сертифікації"</string>
<string name="disable_vpn" msgid="482685974985502922">"Вимкнути VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Від’єднатися від мережі VPN"</string>
@@ -556,8 +568,8 @@
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Адміністратор організації встановив центр сертифікації на цьому пристрої. Захищений мережевий трафік може відстежуватися або змінюватися."</string>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Адміністратор організації встановив центр сертифікації у вашому робочому профілі. Захищений мережевий трафік може відстежуватися або змінюватися."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"На цьому пристрої встановлено центр сертифікації. Захищений мережевий трафік може відстежуватися або змінюватися."</string>
- <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Ваш адміністратор увімкнув реєстрацію в мережі, під час якої на вашому пристрої відстежується трафік."</string>
- <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Ваш адміністратор увімкнув реєстрацію в журналі мережі, щоб відстежувати трафік вашого робочого профілю (не особистого)."</string>
+ <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Ваш адміністратор увімкнув журнал мережі, щоб відстежувати трафік на вашому пристрої."</string>
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Ваш адміністратор увімкнув журнал мережі, щоб відстежувати трафік вашого робочого профілю (не особистого)."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Під’єднано додаток <xliff:g id="VPN_APP">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, як-от відкривання електронних листів, додатків і веб-сайтів."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Під’єднано додатки <xliff:g id="VPN_APP_1">%2$s</xliff:g> та <xliff:g id="VPN_APP_0">%1$s</xliff:g>, які можуть відстежувати вашу активність у мережі, як-от відкривання електронних листів, додатків і веб-сайтів."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Ваш робочий профіль під’єднано до додатка <xliff:g id="VPN_APP">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
@@ -572,7 +584,7 @@
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"Відкрити налаштування мережі VPN"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Відкрити надійні облікові дані"</string>
- <string name="monitoring_description_network_logging" msgid="577305979174002252">"Ваш адміністратор увімкнув реєстрацію в мережі, під час якої на вашому пристрої відстежується трафік.\n\nЩоб дізнатися більше, зв’яжіться з адміністратором."</string>
+ <string name="monitoring_description_network_logging" msgid="577305979174002252">"Ваш адміністратор увімкнув журнал мережі, щоб відстежувати трафік на вашому пристрої.\n\nЩоб дізнатися більше, зв’яжіться з адміністратором."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Ви дозволили додатку під’єднуватися до мережі VPN.\n\nЦей додаток може відстежувати вашу активність на пристрої та в мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Вашим робочим профілем керує адміністратор організації <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВін може відстежувати ваші дії в мережі, зокрема електронні листи, додатки та веб-сайти.\n\nЩоб дізнатися більше, зв’яжіться з адміністратором.\n\nВаш пристрій також під’єднано до мережі VPN, у якій можна відстежувати ваші дії в мережі."</string>
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Цим пристроєм керують твої батьки. Вони можуть бачити та контролювати, якими додатками ти користуєшся, де перебуваєш і скільки часу проводиш за пристроєм."</string>
@@ -663,18 +675,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Сигнал"</string>
<string name="wallet_title" msgid="5369767670735827105">"Гаманець"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Готово"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Налаштувати платіж"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string>
<string name="status_bar_work" msgid="5238641949837091056">"Робочий профіль"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Режим польоту"</string>
<string name="add_tile" msgid="6239678623873086686">"Додавання опції"</string>
@@ -743,11 +751,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус</b>: знижено до \"Без звуку\""</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Статус</b>: пріоритет підвищено"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Статус</b>: пріоритет знижено"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Завжди відображаються вгорі списку сповіщень, навіть коли ввімкнено режим пріоритетності"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Важливі розмови"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Цю групу сповіщень не можна налаштувати тут"</string>
@@ -1025,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Розмову призначено важливою"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Важливі розмови"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Ці розмови відображаються вгорі списку, і ви завжди можете їх побачити, якщо ввімкнено режим пріоритетності"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Зображення профілів видно на заблокованому екрані"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Для зручності ці розмови відображаються в спливаючих чатах на головному екрані"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Переривають режим \"Не турбувати\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Налаштування"</string>
@@ -1050,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Щоб тимчасово сховати кнопку, перемістіть її на край екрана"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перемістити ліворуч угору"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перемістити праворуч угору"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Перемістити ліворуч униз"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Перемістити праворуч униз"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перемістити до краю, приховати"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перемістити від краю, показати"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Керування пристроями"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додайте елементи керування для підключених пристроїв"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Налаштувати елементи керування пристроями"</string>
@@ -1142,35 +1138,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Менше ніж <xliff:g id="DURATION">%1$s</xliff:g> тому"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Понад <xliff:g id="DURATION">%1$s</xliff:g> тому"</string>
<string name="birthday_status" msgid="2596961629465396761">"День народження"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Сьогодні <xliff:g id="NAME">%1$s</xliff:g> святкує День народження"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Скоро іменини"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g> скоро святкуватиме День народження"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Річниця"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Сьогодні <xliff:g id="NAME">%1$s</xliff:g> відзначає річницю"</string>
<string name="location_status" msgid="1294990572202541812">"Ділюся геоданими"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> ділиться своїм місцезнаходженням"</string>
<string name="new_story_status" msgid="9012195158584846525">"Нова історія"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> ділиться новою історією"</string>
<string name="video_status" msgid="4548544654316843225">"Дивлюся відео"</string>
<string name="audio_status" msgid="4237055636967709208">"Слухаю аудіо"</string>
<string name="game_status" msgid="1340694320630973259">"Граю в гру"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Друзі"</string>
<string name="empty_status" msgid="5938893404951307749">"Поспілкуймося!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Незабаром тут з\'явиться контент"</string>
<string name="missed_call" msgid="4228016077700161689">"Пропущений виклик"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Переглядайте останні повідомлення, пропущені виклики й оновлення статусу"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Розмова"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> надсилає повідомлення"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> надсилає зображення"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не вдалось отримати дані лічильника акумулятора"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Натисніть, щоб дізнатися більше"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Немає будильників"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0ec904f2..5f322d5 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"مزید کیپچر کریں"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"اسکرین شاٹ برخاست کریں"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"اسکرین شاٹ کا پیش منظر"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"اوپر کا احاطہ"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"نیچے کا احاطہ"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"سکرین ریکارڈر"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string>
@@ -349,8 +355,14 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ان پٹ کا طریقہ"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"مقام"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"مقام آف"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"کیمرا مسدود کریں"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"مائیکروفون خاموش کریں"</string>
+ <!-- no translation found for quick_settings_camera_label (5612076679385269339) -->
+ <skip />
+ <!-- no translation found for quick_settings_mic_label (8392773746295266375) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_available (1453719768420394314) -->
+ <skip />
+ <!-- no translation found for quick_settings_camera_mic_blocked (4710884905006788281) -->
+ <skip />
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"میڈیا آلہ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"صرف ہنگامی کالیں"</string>
@@ -422,8 +434,18 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"اسکرین ریکارڈر کریں"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"آغاز"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"روکیں"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"جاری رکھنے کیلئے <b><xliff:g id="APP">%s</xliff:g></b> کو آپ کے آلے کے مائیکروفون تک رسائی درکار ہے۔"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"جاری رکھنے کیلئے <b><xliff:g id="APP">%s</xliff:g></b> کو آپ کے آلے کے کیمرے تک رسائی درکار ہے۔"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_title (563796653825944944) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_title (8807639852654305227) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_title (4316471859905020023) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_dialog_content (1624701280680913717) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_dialog_content (4704948062372435963) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_mic_camera_dialog_content (3577642558418404919) -->
+ <skip />
<string name="media_seamless_remote_device" msgid="177033467332920464">"آلہ"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"ایپس سوئچ کرنے کیلئے اوپر سوائپ کریں"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"تیزی سے ایپس کو سوئچ کرنے کے لیے دائیں طرف گھسیٹیں"</string>
@@ -657,18 +679,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"ایتھرنیٹ"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"الارم"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"تیار ہے"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"ادائیگی سیٹ اپ کریں"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"استعمال کرنے کے لیے غیر مقفل کریں"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"آپ کے کارڈز حاصل کرنے میں ایک مسئلہ درپیش تھا، براہ کرم بعد میں دوبارہ کوشش کریں"</string>
<string name="status_bar_work" msgid="5238641949837091056">"دفتری پروفائل"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ہوائی جہاز وضع"</string>
<string name="add_tile" msgid="6239678623873086686">"ٹائل شامل کریں"</string>
@@ -737,11 +755,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>اسٹیٹس:</b> کو خاموش پر درجہ بند کیا گیا"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>اسٹیٹس:</b> کو اعلی درجہ دیا گیا"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>اسٹیٹس:</b> کو کم درجہ دیا گیا"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"ترجیحی موڈ آن ہونے پر بھی، ہمیشہ آپ کی اطلاعات کے اوپری حصے میں دکھائی جاتی ہے"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ترتیبات"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"ترجیحی گفتگوئیں"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو کی خصوصیات کو سپورٹ نہیں کرتا ہے"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"اطلاعات کے اس گروپ کو یہاں کنفیگر نہیں کیا جا سکتا"</string>
@@ -1015,14 +1031,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"گفتگو کو ترجیح پر سیٹ کیا گیا"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"ترجیحی گفتگوئیں"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"یہ گفتگوئیں آپ کی فہرست کے اوپری حصے میں دکھائ جاتی ہیں اور جب آپ کا ترجیحی موڈ آن ہوتا ہے تو ہمیشہ آپ تک پہنچ سکتی ہیں"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"پروفائل کی تصاویر مقفل اسکرین پر دکھائی جاتی ہیں"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"آپ ان مکالموں کو آسانی سے اپنی ہوم اسکرین پر بلبلوں میں تلاش کر سکتے ہیں"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ڈسٹرب نہ کریں میں مداخلت کریں"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"سمجھ آ گئی"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ترتیبات"</string>
@@ -1040,18 +1052,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"عارضی طور پر بٹن کو چھپانے کے لئے اسے کنارے پر لے جائیں"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"اوپر بائیں جانب لے جائیں"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"اوپر دائیں جانب لے جائيں"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"نیچے بائیں جانب لے جائیں"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"نیچے دائیں جانب لے جائیں"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"EDGE پر لے جائیں اور چھپائیں"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"EDGE اور شو سے باہر منتقل کریں"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"آلہ کے کنٹرولز"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"اپنے منسلک آلات کے لیے کنٹرولز شامل کریں"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"آلہ کے کنٹرولز سیٹ اپ کریں"</string>
@@ -1130,35 +1136,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g> سے کچھ کم وقت قبل"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g> سے زائد عرصہ قبل"</string>
<string name="birthday_status" msgid="2596961629465396761">"سالگرہ"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> کی سالگرہ ہے"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"سالگرہ قریب ہے"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"جلدی ہی <xliff:g id="NAME">%1$s</xliff:g> کی سالگرہ ہے"</string>
<string name="anniversary_status" msgid="1790034157507590838">"سالگرہ"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> کی سالگرہ ہے"</string>
<string name="location_status" msgid="1294990572202541812">"مقام کا اشتراک کیا جا رہا ہے"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> مقام کا اشتراک کر رہا ہے"</string>
<string name="new_story_status" msgid="9012195158584846525">"نئی کہانی"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک نئی کہانی کا اشتراک کیا"</string>
<string name="video_status" msgid="4548544654316843225">"دیکھ رہے ہیں"</string>
<string name="audio_status" msgid="4237055636967709208">"سنی جا رہی ہے"</string>
<string name="game_status" msgid="1340694320630973259">"کھیلی جا رہی ہے"</string>
<string name="empty_user_name" msgid="3389155775773578300">"دوست"</string>
<string name="empty_status" msgid="5938893404951307749">"آج رات چیٹ کرتے ہیں!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"مواد جلد ہی نظر آئے گا"</string>
<string name="missed_call" msgid="4228016077700161689">"چھوٹی ہوئی کال"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"حالیہ پیغامات، چھوٹی ہوئی کالز اور اسٹیٹس اپ ڈیٹس دیکھیں"</string>
<string name="people_tile_title" msgid="6589377493334871272">"گفتگو"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک پیغام بھیجا"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک تصویر بھیجی"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"آپ کے بیٹری میٹر کو پڑھنے میں دشواری"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"مزید معلومات کے لیے تھپتھپائیں"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"کوئی الارم سیٹ نہیں ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 66cecef..86d1e5f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Yana suratga olish"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Skrinshotni yopish"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Skrinshotga razm solish"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Yuqori chegara"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Quyi chegara"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Kiritish usuli"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Joylashuvni aniqlash xizmati yoqilmagan"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Kamerani bloklash"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mikrofonni ovozsiz qilish"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraga ruxsat"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonga ruxsat"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Mavjud"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloklangan"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media qurilma"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Favqulodda chaqiruvlar"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekranni yozib olish"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Boshlash"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Toʻxtatish"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Davom etish uchun <b> <xliff:g id="APP">%s</xliff:g></b> mikrofoningizdan foydalanishi kerak."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Davom etish uchun <b><xliff:g id="APP">%s</xliff:g></b> qurilmangiz kamerasiga kirishi kerak."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Qurilma mikrofoni blokdan chiqarilsinmi?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Qurilma kamerasi blokdan chiqarilsinmi?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Qurilma kamerasi va mikrofoni blokdan chiqarilsinmi?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Mikrofoningizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamerangizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera va mikrofoningizdan foydalanishga ruxsat berilgan barcha ilovalar va xizmatlar uchun ruxsatni blokdan chiqaradi."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Qurilma"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Ilovalarni almashtirish uchun ekranni tepaga suring"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Ilovalarni tezkor almashtirish uchun o‘ngga torting"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Signal"</string>
<string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Tayyor"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Toʻlovni sozlash"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Foydalanish uchun qulfdan chiqarish"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Bildirgilarni yuklashda xatolik yuz berdi, keyinroq qaytadan urining"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string>
<string name="add_tile" msgid="6239678623873086686">"Tezkor sozlamalar tugmasini qo‘shish"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Holati:</b> Sokin darajaga tushirildi"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Holati:</b> Yuqori darajaga chiqarildi"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Holati:</b> Quyi darajaga tushirildi"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"“Faqat muhim” rejimi yoniq boʻlsa ham doimo bildirishnomalaringizning tepasida chiqadi"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Sozlamalar"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Muhim suhbatlar"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Tizim navigatsiyasini yangilash uchun Sozlamalarni oching"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Suhbat muhim deb belgilandi"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Muhim suhbatlar"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Bu suhbatlar roʻyxat yuqorisida chiqadi va “M|uhim” rejimi yoniq boʻlganda oʻqish mumkin"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Profil rasmlari ekran qulfida chiqadi"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Bu suhbatlarni osongina bosh ekrandagi bulutchalardan topishingiz mumkin"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Bezovta qilinmasin rejimida chiqarish"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Sozlamalar"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Almashtirish"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Maxsus imkoniyatlar tugmasi maxsus imkoniyatlar ishorasini almashtirdi\n\n"<annotation id="link">"Sozlamalarni ochish"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Vaqtinchalik berkitish uchun tugmani qirra tomon suring"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuqori chapga surish"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuqori oʻngga surish"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Quyi chapga surish"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Quyi oʻngga surish"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chetiga olib borish va yashirish"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chetidan qaytarish va koʻrsatish"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ulangan qurilmalar uchun boshqaruv elementlari"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Qurilma boshqaruv elementlarini sozlash"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"<xliff:g id="DURATION">%1$s</xliff:g>dan kam vaqt oldin"</string>
<string name="over_timestamp" msgid="4765793502859358634">"<xliff:g id="DURATION">%1$s</xliff:g>dan ortiq vaqt oldin"</string>
<string name="birthday_status" msgid="2596961629465396761">"Tavallud kuni"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"<xliff:g id="NAME">%1$s</xliff:g> tavallud ayyomi"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Yaqinda tavallud kun"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Tez orada <xliff:g id="NAME">%1$s</xliff:g> tavallud ayyomini nishonlaydi"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Yubiley"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"<xliff:g id="NAME">%1$s</xliff:g> yubileyi"</string>
<string name="location_status" msgid="1294990572202541812">"Joylashuv ulashilmoqda"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> joylashuvni ulashmoqda"</string>
<string name="new_story_status" msgid="9012195158584846525">"Yangi hikoya"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> yangi hikoyani ulashdi"</string>
<string name="video_status" msgid="4548544654316843225">"Tomosha"</string>
<string name="audio_status" msgid="4237055636967709208">"Gapiring"</string>
<string name="game_status" msgid="1340694320630973259">"Ijro etilmoqda"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Doʻstlar"</string>
<string name="empty_status" msgid="5938893404951307749">"Bugun yozishaylik!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Kontent tezda chiqadi"</string>
<string name="missed_call" msgid="4228016077700161689">"Javobsiz chaqiruv"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Oxirgi xabarlar, javobsiz chaqiruvlar va holat yangilanishlari"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Suhbat"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> xabar yubordi"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> rasm yubordi"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya quvvati aniqlanmadi"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Batafsil axborot olish uchun bosing"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Signal sozlanmagan"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index dfcce49..3afa405 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Chụp được nhiều hơn"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Đóng ảnh chụp màn hình"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Xem trước ảnh chụp màn hình"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Ranh giới trên"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Ranh giới dưới"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Trình ghi màn hình"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Đang xử lý video ghi màn hình"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Thông báo đang diễn ra về phiên ghi màn hình"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Phương thức nhập"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Tắt vị trí"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Chặn máy ảnh"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Tắt tiếng micrô"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Quyền truy cập vào máy ảnh"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Quyền truy cập vào micrô"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Được phép"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bị chặn"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Thiết bị phương tiện"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chỉ cuộc gọi khẩn cấp"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ghi lại nội dung trên màn hình"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Bắt đầu"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dừng"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Để tiếp tục, <b><xliff:g id="APP">%s</xliff:g></b> cần quyền truy cập vào micrô trên thiết bị của bạn."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Để tiếp tục, <b><xliff:g id="APP">%s</xliff:g></b> cần quyền truy cập vào máy ảnh trên thiết bị của bạn."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Bỏ chặn micrô của thiết bị?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Bỏ chặn máy ảnh của thiết bị?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Bỏ chặn máy ảnh và micrô của thiết bị?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng micrô của bạn."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng máy ảnh của bạn."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Thao tác này sẽ bỏ chặn quyền truy cập cho mọi ứng dụng và dịch vụ được phép sử dụng máy ảnh hoặc micrô của bạn."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Thiết bị"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Vuốt lên để chuyển đổi ứng dụng"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Kéo sang phải để chuyển đổi nhanh giữa các ứng dụng"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"Báo thức"</string>
<string name="wallet_title" msgid="5369767670735827105">"Ví"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"Sẵn sàng"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Thiết lập phương thức thanh toán"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Mở khóa để sử dụng"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"Đã xảy ra sự cố khi tải thẻ của bạn. Vui lòng thử lại sau"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ máy bay"</string>
<string name="add_tile" msgid="6239678623873086686">"Thêm ô"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Trạng thái:</b> Đã thay đổi thành Im lặng"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Trạng thái:</b> Đã tăng mức độ quan trọng"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Trạng thái:</b> Đã giảm mức độ quan trọng"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"Luôn hiển thị ở đầu thông báo, ngay cả khi Chế độ ưu tiên đang bật"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cài đặt"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"Cuộc trò chuyện ưu tiên"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ các tính năng trò chuyện"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Không thể định cấu hình nhóm thông báo này tại đây"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Chuyển đến phần Cài đặt để cập nhật chế độ di chuyển trên hệ thống"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"Đặt cuộc trò chuyện thành ưu tiên"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"Cuộc trò chuyện ưu tiên"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"Các cuộc trò chuyện này hiển thị ở đầu danh sách và luôn trong tầm nhìn của bạn khi Chế độ ưu tiên đang bật"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"Ảnh hồ sơ hiển thị trên màn hình khóa"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"Bạn có thể dễ dàng tìm thấy những cuộc trò chuyện này trong bong bóng trò chuyện trên Màn hình chính"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Làm gián đoạn chế độ Không làm phiền"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Cài đặt"</string>
@@ -1040,18 +1042,12 @@
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Chuyển"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Nút hỗ trợ tiếp cận đã thay thế cử chỉ hỗ trợ tiếp cận\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Di chuyển nút sang cạnh để ẩn nút tạm thời"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Chuyển lên trên cùng bên trái"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Chuyển lên trên cùng bên phải"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Chuyển tới dưới cùng bên trái"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Chuyển tới dưới cùng bên phải"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chuyển đến cạnh và ẩn"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chuyển ra xa cạnh và hiển thị"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Thêm các tùy chọn điều khiển cho các thiết bị đã kết nối của bạn"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Thiết lập các tùy chọn điều khiển thiết bị"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"Chưa đầy <xliff:g id="DURATION">%1$s</xliff:g> trước"</string>
<string name="over_timestamp" msgid="4765793502859358634">"Hơn <xliff:g id="DURATION">%1$s</xliff:g> trước"</string>
<string name="birthday_status" msgid="2596961629465396761">"Sinh nhật"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"Hôm nay là sinh nhật của <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Sắp đến sinh nhật"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"Sắp đến sinh nhật của <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="anniversary_status" msgid="1790034157507590838">"Ngày kỷ niệm"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"Hôm nay là ngày kỷ niệm của <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="location_status" msgid="1294990572202541812">"Đang chia sẻ vị trí"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g> đang chia sẻ thông tin vị trí"</string>
<string name="new_story_status" msgid="9012195158584846525">"Tin bài mới"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g> đã chia sẻ một tin bài mới"</string>
<string name="video_status" msgid="4548544654316843225">"Đang xem"</string>
<string name="audio_status" msgid="4237055636967709208">"Đang nghe"</string>
<string name="game_status" msgid="1340694320630973259">"Đang chơi"</string>
<string name="empty_user_name" msgid="3389155775773578300">"Bạn bè"</string>
<string name="empty_status" msgid="5938893404951307749">"Cùng trò chuyện tối nay nhé!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"Nội dung sẽ sớm hiển thị"</string>
<string name="missed_call" msgid="4228016077700161689">"Cuộc gọi nhỡ"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Hơn <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Xem các tin nhắn, cuộc gọi nhỡ và thông tin cập nhật trạng thái gần đây"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Cuộc trò chuyện"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một tin nhắn"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một hình ảnh"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Đã xảy ra vấn đề khi đọc dung lượng pin của bạn"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Nhấn để biết thêm thông tin"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Chưa đặt chuông báo"</string>
diff --git a/packages/SystemUI/res/values-w550dp-land/config.xml b/packages/SystemUI/res/values-w550dp-land/config.xml
deleted file mode 100644
index a33f131..0000000
--- a/packages/SystemUI/res/values-w550dp-land/config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <integer name="quick_settings_num_columns">6</integer>
-</resources>
diff --git a/packages/SystemUI/res/values-w650dp-land/dimens.xml b/packages/SystemUI/res/values-w650dp-land/dimens.xml
index 108d6cf..97b6da1 100644
--- a/packages/SystemUI/res/values-w650dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-w650dp-land/dimens.xml
@@ -16,6 +16,5 @@
-->
<resources>
<!-- Standard notification width + gravity -->
- <dimen name="notification_panel_width">644dp</dimen>
-
+ <dimen name="notification_panel_width">-1px</dimen> <!-- match_parent -->
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 96a7ae0..edef559 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"截取更多内容"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"关闭屏幕截图"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"屏幕截图预览"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"顶部边界"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"底部边界"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"屏幕录制器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"输入法"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置信息"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"位置信息:关闭"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"停用摄像头"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"将麦克风静音"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"摄像头使用权限"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"麦克风使用权限"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"已允许"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"已禁用"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"媒体设备"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"只能拨打紧急呼救电话"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"屏幕录制"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"开始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"如要继续操作,请向<b><xliff:g id="APP">%s</xliff:g></b>授予设备的麦克风使用权。"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"如要继续操作,请向<b><xliff:g id="APP">%s</xliff:g></b>授予设备的相机使用权。"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要取消禁用设备麦克风吗?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要取消禁用设备摄像头吗?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要取消禁用设备摄像头和麦克风吗?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"这将会为所有获准使用您麦克风的应用和服务启用这项权限。"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"这将会为所有获准使用您摄像头的应用和服务启用这项权限。"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"这将会为所有获准使用您摄像头或麦克风的应用和服务启用这项权限。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"设备"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"向上滑动可切换应用"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"向右拖动可快速切换应用"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"以太网"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"闹钟"</string>
<string name="wallet_title" msgid="5369767670735827105">"电子钱包"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"已可使用"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"设置付款方式"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解锁设备即可使用"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"获取您的卡片时出现问题,请稍后重试"</string>
<string name="status_bar_work" msgid="5238641949837091056">"工作资料"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"飞行模式"</string>
<string name="add_tile" msgid="6239678623873086686">"添加图块"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>状态</b>:已降低为“静音”"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>状态</b>:已调高顺序"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>状态</b>:已调低顺序"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"始终显示在通知列表的顶部,即使“优先”模式处于开启状态也是如此"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"设置"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"优先对话"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"您无法在此处配置这组通知"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"转到“设置”即可更新系统导航"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"已设置为优先对话"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"优先对话"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"“优先”模式处于开启状态时,这些对话会显示在对话列表顶部,并且始终显示在屏幕上"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"个人资料照片会显示在锁定屏幕上"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"这些对话会以对话泡形式显示在主屏幕上,您可以轻松查看"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"中断勿扰模式"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"知道了"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"设置"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"将按钮移到边缘,即可暂时将其隐藏"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移至左上角"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移至右上角"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"移至左下角"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移至右下角"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移至边缘并隐藏"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"移至边缘以外并显示"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"设备控制器"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"为您所连接的设备添加控件"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"设置设备控件"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"最近 <xliff:g id="DURATION">%1$s</xliff:g>内"</string>
<string name="over_timestamp" msgid="4765793502859358634">"超过 <xliff:g id="DURATION">%1$s</xliff:g>前"</string>
<string name="birthday_status" msgid="2596961629465396761">"生日"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"今天是<xliff:g id="NAME">%1$s</xliff:g>的生日"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"生日快到了"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g>的生日快到了"</string>
<string name="anniversary_status" msgid="1790034157507590838">"周年纪念日"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"今天是<xliff:g id="NAME">%1$s</xliff:g>的周年纪念日"</string>
<string name="location_status" msgid="1294990572202541812">"正在分享位置信息"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g>正在分享位置信息"</string>
<string name="new_story_status" msgid="9012195158584846525">"新故事"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>分享了一个新故事"</string>
<string name="video_status" msgid="4548544654316843225">"正在观看"</string>
<string name="audio_status" msgid="4237055636967709208">"正在收听"</string>
<string name="game_status" msgid="1340694320630973259">"正在玩游戏"</string>
<string name="empty_user_name" msgid="3389155775773578300">"好友"</string>
<string name="empty_status" msgid="5938893404951307749">"今晚来聊聊吧!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"内容很快就会显示,请稍候"</string>
<string name="missed_call" msgid="4228016077700161689">"未接电话"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"查看最近的信息、未接电话和状态更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"对话"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>发送了一条消息"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>发送了一张图片"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"读取电池计量器时出现问题"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"点按即可了解详情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未设置闹钟"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5f51239..34fb635 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"擷取更大範圍的螢幕內容"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"關閉螢幕截圖"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"上方邊界"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"下方邊界"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕畫面錄影工具"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示錄影畫面工作階段通知"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"輸入法"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"位置"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"位置資訊已關閉"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"停用攝錄機"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"關閉麥克風"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"相機存取權"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"麥克風存取權"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"可用"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"已封鎖"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"媒體裝置"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"只可撥打緊急電話"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"畫面錄影"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"如要繼續,<b><xliff:g id="APP">%s</xliff:g></b> 需要裝置的麥克風存取權。"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"如要繼續,<b><xliff:g id="APP">%s</xliff:g></b> 需要裝置的相機存取權。"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解除封鎖裝置相機和麥克風嗎?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"這麼做可允許所有應用程式和服務使用麥克風。"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"這麼做可允許所有應用程式和服務使用相機。"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"這麼做可允許所有應用程式和服務使用相機或麥克風。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"裝置"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"向上滑動即可切換應用程式"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"向右拖曳即可快速切換應用程式"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"以太網"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"鬧鐘"</string>
<string name="wallet_title" msgid="5369767670735827105">"電子錢包"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"準備就緒"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"設定付款方法"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"擷取資訊卡時發生問題,請稍後再試。"</string>
<string name="status_bar_work" msgid="5238641949837091056">"工作設定檔"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"飛行模式"</string>
<string name="add_tile" msgid="6239678623873086686">"加入圖塊"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>狀態:</b>已降低為靜音"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>狀態:</b>已提高次序"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>狀態:</b>已調低次序"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"無論是否開啟「優先」模式,一律在通知頂端顯示"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"優先對話"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在此設定這組通知"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"前往「設定」更新系統導覽"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"對話已設為優先"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"優先對話"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"開啟「優先」模式後,這些對話會顯示在清單頂端,讓您一眼就能看見"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"上鎖畫面會顯示個人檔案相片"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"主畫面上會以對話氣泡顯示這些對話,讓您一眼就能看見"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"中斷「請勿騷擾」"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"知道了"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
@@ -1040,18 +1042,12 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣即可暫時隱藏"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移去左上方"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移去右上方"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"移到左下方"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移去右下方"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"為連接的裝置新增控制選項"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"最近 <xliff:g id="DURATION">%1$s</xliff:g>內"</string>
<string name="over_timestamp" msgid="4765793502859358634">"超過 <xliff:g id="DURATION">%1$s</xliff:g>前"</string>
<string name="birthday_status" msgid="2596961629465396761">"生日之星"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"今天是<xliff:g id="NAME">%1$s</xliff:g>的生日"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"即將生日"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g>的生日快到了"</string>
<string name="anniversary_status" msgid="1790034157507590838">"週年紀念"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"今天是<xliff:g id="NAME">%1$s</xliff:g>的週年紀念"</string>
<string name="location_status" msgid="1294990572202541812">"分享位置資訊"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g>正在分享位置"</string>
<string name="new_story_status" msgid="9012195158584846525">"最新報導"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>分享了新的動態消息"</string>
<string name="video_status" msgid="4548544654316843225">"正在觀看"</string>
<string name="audio_status" msgid="4237055636967709208">"正在聽取音訊"</string>
<string name="game_status" msgid="1340694320630973259">"正在玩遊戲"</string>
<string name="empty_user_name" msgid="3389155775773578300">"朋友"</string>
<string name="empty_status" msgid="5938893404951307749">"今晚聊天吧!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"即將顯示內容"</string>
<string name="missed_call" msgid="4228016077700161689">"未接來電"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"對話"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>傳送了訊息"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了圖片"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕按即可瞭解詳情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 8d6ac87..0fba423 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"擷取更大範圍的螢幕內容"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"關閉螢幕截圖"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"頂端邊界"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"底部邊界"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕錄影器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string>
@@ -217,7 +223,7 @@
<string name="accessibility_no_sim" msgid="1140839832913084973">"沒有 SIM 卡。"</string>
<string name="accessibility_cell_data" msgid="172950885786007392">"行動數據"</string>
<string name="accessibility_cell_data_on" msgid="691666434519443162">"行動數據已開啟"</string>
- <string name="cell_data_off" msgid="4886198950247099526">"已關閉"</string>
+ <string name="cell_data_off" msgid="4886198950247099526">"關閉"</string>
<string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"藍牙網路共用"</string>
<string name="accessibility_airplane_mode" msgid="1899529214045998505">"飛行模式。"</string>
<string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN 已開啟。"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"輸入法"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"定位"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"定位服務已關閉"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"停用攝影機"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"關閉麥克風"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"相機存取權"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"麥克風存取權"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"可以使用"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"已封鎖"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"媒體裝置"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"僅可撥打緊急電話"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"螢幕畫面錄製"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"如要繼續操作,請將裝置的麥克風存取權授予「<xliff:g id="APP">%s</xliff:g>」<b></b>。"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"如要繼續操作,請將裝置的相機存取權授予「<xliff:g id="APP">%s</xliff:g>」<b></b>。"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要將裝置麥克風解除封鎖嗎?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要將裝置相機解除封鎖嗎?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要將裝置的相機和麥克風解除封鎖嗎?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"這麼做可允許所有應用程式和服務使用麥克風。"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"這麼做可允許所有應用程式和服務使用相機。"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"這麼做可允許所有應用程式和服務使用相機或麥克風。"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"裝置"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"向上滑動即可切換應用程式"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"向右拖曳即可快速切換應用程式"</string>
@@ -657,18 +669,14 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"乙太網路"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"鬧鐘"</string>
<string name="wallet_title" msgid="5369767670735827105">"電子錢包"</string>
- <!-- no translation found for wallet_button_label_device_unlocked (4653372304880486681) -->
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
<skip />
- <!-- no translation found for wallet_button_label_device_locked (4418473374652969487) -->
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
<skip />
- <!-- no translation found for wallet_secondary_label_active (4909706168969888137) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_no_card (1750103386908123401) -->
- <skip />
- <!-- no translation found for wallet_secondary_label_device_locked (5175862019125370506) -->
- <skip />
- <!-- no translation found for wallet_error_generic (257704570182963611) -->
- <skip />
+ <string name="wallet_secondary_label_active" msgid="4909706168969888137">"已可使用"</string>
+ <string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"設定付款方式"</string>
+ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
+ <string name="wallet_error_generic" msgid="257704570182963611">"擷取卡片時發生問題,請稍後再試"</string>
<string name="status_bar_work" msgid="5238641949837091056">"工作資料夾"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"飛航模式"</string>
<string name="add_tile" msgid="6239678623873086686">"新增圖塊"</string>
@@ -737,11 +745,9 @@
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>狀態:</b>已降低為靜音"</string>
<string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>狀態:</b>已調高順序"</string>
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>狀態:</b>已調降順序"</string>
- <!-- no translation found for notification_channel_summary_priority (4592979359953954258) -->
- <skip />
+ <string name="notification_channel_summary_priority" msgid="4592979359953954258">"一律顯示在通知頂端 (無論是否開啟「優先」模式)"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
- <!-- no translation found for notification_priority_title (5256226572739882190) -->
- <skip />
+ <string name="notification_priority_title" msgid="5256226572739882190">"優先對話"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在這裡設定這個通知群組"</string>
@@ -1015,14 +1021,10 @@
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"請前往「設定」更新系統操作機制"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
<string name="priority_onboarding_title" msgid="2893070698479227616">"對話已設為優先"</string>
- <!-- no translation found for priority_onboarding_behavior (636826237468953117) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_at_top_text (3861580571311518785) -->
- <skip />
- <!-- no translation found for priority_onboarding_show_avatar_text (1781653813573865071) -->
- <skip />
- <!-- no translation found for priority_onboarding_appear_as_bubble_text (4359924720680083057) -->
- <skip />
+ <string name="priority_onboarding_behavior" msgid="636826237468953117">"優先對話"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="3861580571311518785">"開啟「優先」模式後,這些對話會顯示在清單頂端,讓你一眼就能看見"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="1781653813573865071">"螢幕鎖定畫面上會顯示個人資料相片"</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4359924720680083057">"主畫面上會以對話框形式顯示這些對話,讓你一眼就能看見"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"中斷零打擾模式"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"我知道了"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
@@ -1040,21 +1042,15 @@
<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>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣處即可暫時隱藏"</string>
- <!-- no translation found for accessibility_floating_button_action_move_top_left (6253520703618545705) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_top_right (6106225581993479711) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_left (8063394111137429725) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_bottom_right (6196904373227440500) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_to_edge_and_hide_to_half (662401168245782658) -->
- <skip />
- <!-- no translation found for accessibility_floating_button_action_move_out_edge_and_show (8354760891651663326) -->
- <skip />
+ <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移到左上方"</string>
+ <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移到右上方"</string>
+ <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"移到左下方"</string>
+ <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移到右下方"</string>
+ <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>
+ <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"新增已連結裝置的控制項"</string>
- <string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string>
+ <string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制項"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"按住電源按鈕即可存取控制項"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
@@ -1077,7 +1073,7 @@
<string name="controls_favorite_load_error" msgid="5126216176144877419">"無法載入控制項。請查看「<xliff:g id="APP">%s</xliff:g>」應用程式,確認應用程式設定沒有任何異動。"</string>
<string name="controls_favorite_load_none" msgid="7687593026725357775">"找不到相容的控制項"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
- <string name="controls_dialog_title" msgid="2343565267424406202">"新增至裝置控制"</string>
+ <string name="controls_dialog_title" msgid="2343565267424406202">"新增至裝置控制項"</string>
<string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"來自「<xliff:g id="APP">%s</xliff:g>」的建議"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string>
@@ -1130,35 +1126,27 @@
<string name="less_than_timestamp" msgid="6598972791137724517">"最近 <xliff:g id="DURATION">%1$s</xliff:g>內"</string>
<string name="over_timestamp" msgid="4765793502859358634">"超過 <xliff:g id="DURATION">%1$s</xliff:g>前"</string>
<string name="birthday_status" msgid="2596961629465396761">"本日壽星"</string>
- <!-- no translation found for birthday_status_content_description (7677415209545817153) -->
- <skip />
+ <string name="birthday_status_content_description" msgid="7677415209545817153">"今天是<xliff:g id="NAME">%1$s</xliff:g>的生日"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"生日快到了"</string>
- <!-- no translation found for upcoming_birthday_status_content_description (1210885672210845293) -->
- <skip />
+ <string name="upcoming_birthday_status_content_description" msgid="1210885672210845293">"<xliff:g id="NAME">%1$s</xliff:g>的生日快到了"</string>
<string name="anniversary_status" msgid="1790034157507590838">"週年紀念"</string>
- <!-- no translation found for anniversary_status_content_description (6214503393960662875) -->
- <skip />
+ <string name="anniversary_status_content_description" msgid="6214503393960662875">"今天是<xliff:g id="NAME">%1$s</xliff:g>的週年紀念日"</string>
<string name="location_status" msgid="1294990572202541812">"正在分享位置資訊"</string>
- <!-- no translation found for location_status_content_description (2982386178160071305) -->
- <skip />
+ <string name="location_status_content_description" msgid="2982386178160071305">"<xliff:g id="NAME">%1$s</xliff:g>正在分享位置資訊"</string>
<string name="new_story_status" msgid="9012195158584846525">"新故事"</string>
- <!-- no translation found for new_story_status_content_description (4963137422622516708) -->
- <skip />
+ <string name="new_story_status_content_description" msgid="4963137422622516708">"<xliff:g id="NAME">%1$s</xliff:g>分享了一篇新故事"</string>
<string name="video_status" msgid="4548544654316843225">"正在觀看影片"</string>
<string name="audio_status" msgid="4237055636967709208">"正在聆聽內容"</string>
<string name="game_status" msgid="1340694320630973259">"正在玩遊戲"</string>
<string name="empty_user_name" msgid="3389155775773578300">"好友"</string>
<string name="empty_status" msgid="5938893404951307749">"今晚來聊聊吧!"</string>
- <!-- no translation found for status_before_loading (1500477307859631381) -->
- <skip />
+ <string name="status_before_loading" msgid="1500477307859631381">"內容很快就會顯示,請稍候"</string>
<string name="missed_call" msgid="4228016077700161689">"未接來電"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"對話"</string>
- <!-- no translation found for new_notification_text_content_description (5574393603145263727) -->
- <skip />
- <!-- no translation found for new_notification_image_content_description (6017506886810813123) -->
- <skip />
+ <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一則訊息"</string>
+ <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一張圖片"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕觸即可瞭解詳情"</string>
<string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"未設定鬧鐘"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 54facec..33ef9da 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -92,8 +92,14 @@
<string name="screenshot_scroll_label" msgid="2930198809899329367">"Thwebula okuningi"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cashisa isithombe-skrini"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ukubuka kuqala isithombe-skrini"</string>
- <string name="screenshot_top_boundary" msgid="1500569103321300856">"Umngcele ophezulu"</string>
- <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Umngcele ophansi"</string>
+ <!-- no translation found for screenshot_top_boundary_pct (2520148599096479332) -->
+ <skip />
+ <!-- no translation found for screenshot_bottom_boundary_pct (3880821519814946478) -->
+ <skip />
+ <!-- no translation found for screenshot_left_boundary_pct (8502323556112287469) -->
+ <skip />
+ <!-- no translation found for screenshot_right_boundary_pct (1201150713021779321) -->
+ <skip />
<string name="screenrecord_name" msgid="2596401223859996572">"Irekhoda yesikrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Isaziso esiqhubekayo seseshini yokurekhoda isikrini"</string>
@@ -349,8 +355,10 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Indlela yokungenayo"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Indawo"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Indawo ivaliwe"</string>
- <string name="quick_settings_camera_label" msgid="1367149596242401934">"Vimba Ikhamera"</string>
- <string name="quick_settings_mic_label" msgid="8245831073612564953">"Thulisa Imakrofoni"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Ukufinyelela kwekhamera"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Ukufinyelela kwe-mic"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Iyatholakala"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Kuvinjiwe"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Idivayisi yemidiya"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Amakholi aphuthumayo kuphela"</string>
@@ -422,8 +430,12 @@
<string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Irekhodi lesikrini"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Qala"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Misa"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="8643239110815357707">"Ukuze uqhubeke, <b>i-<xliff:g id="APP">%s</xliff:g></b> idinga ukufinyelela imakrofoni yedivayisi yakho."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="7773612142162829116">"Ukuze uqhubeke, <b>i-<xliff:g id="APP">%s</xliff:g></b> idinga ukufinyelela ikhamera yakho."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vulela imakrofoni yedivayisi?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vulela ikhamera yedivayisi?"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vulela ikhamera yedivayisi nemakrofoni?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa imakrofoni yakho."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa ikhamera yakho."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Lokhu kuvulela ukufinyelela kwawo wonke ama-app namasevisi avunyelwe ukusebenzisa ikhamera yakho noma imakrofoni."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Idivayisi"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swayiphela phezulu ukuze ushintshe izinhlelo zokusebenza"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Hudula ngqo ukuze ushintshe ngokushesha izinhlelo zokusebenza"</string>
@@ -657,8 +669,10 @@
<string name="status_bar_ethernet" msgid="5690979758988647484">"I-Ethernet"</string>
<string name="status_bar_alarm" msgid="87160847643623352">"I-alamu"</string>
<string name="wallet_title" msgid="5369767670735827105">"I-wallet"</string>
- <string name="wallet_button_label_device_unlocked" msgid="4653372304880486681">"Bonisa konke"</string>
- <string name="wallet_button_label_device_locked" msgid="4418473374652969487">"Vula ukuze ukhokhele"</string>
+ <!-- no translation found for wallet_app_button_label (7123784239111190992) -->
+ <skip />
+ <!-- no translation found for wallet_action_button_label_unlock (8663239748726774487) -->
+ <skip />
<string name="wallet_secondary_label_active" msgid="4909706168969888137">"Isikulungele"</string>
<string name="wallet_secondary_label_no_card" msgid="1750103386908123401">"Setha inkokhelo"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Vula ukuze usebenzise"</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index e4bdbf3..f489fe8 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -176,10 +176,6 @@
<attr name="android:alpha" />
</declare-styleable>
- <declare-styleable name="PagedTileLayout">
- <attr name="sideLabels" format="boolean"/>
- </declare-styleable>
-
<declare-styleable name="CropView">
<attr name="handleThickness" />
<attr name="handleColor" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f699198..bf13c21 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -157,7 +157,6 @@
<color name="minimize_dock_shadow_end">#00000000</color>
<color name="default_remote_input_background">@*android:color/notification_default_color</color>
- <color name="notif_pill_background">@*android:color/surface_light</color>
<color name="notif_pill_text">@android:color/system_neutral1_900</color>
<color name="remote_input_accent">?android:attr/colorAccent</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2355650..5feb957 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -86,13 +86,13 @@
<bool name="config_navigation_bar_enable_auto_dim_no_visible_wallpaper">true</bool>
<!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_columns">6</integer>
+ <integer name="quick_qs_panel_max_columns">4</integer>
<!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">3</integer>
+ <integer name="quick_settings_num_columns">2</integer>
<!-- The number of rows in the QuickSettings -->
- <integer name="quick_settings_max_rows">3</integer>
+ <integer name="quick_settings_max_rows">4</integer>
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">1</integer>
@@ -656,4 +656,10 @@
<!-- Y -->
<!-- radius -->
</integer-array>
+
+ <!-- Overrides the behavior of the face unlock keyguard bypass setting:
+ 0 - Don't override the setting (default)
+ 1 - Override the setting to always bypass keyguard
+ 2 - Override the setting to never bypass keyguard -->
+ <integer name="config_face_unlock_bypass_override">0</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a19d128..62ac75e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -407,10 +407,12 @@
<!-- The height of the quick settings footer that holds the user switcher, settings icon,
etc. -->
- <dimen name="qs_footer_height">48dp</dimen>
+ <dimen name="qs_footer_height">96dp</dimen>
<!-- The size of each of the icon buttons in the QS footer -->
- <dimen name="qs_footer_action_button_size">@dimen/qs_footer_height</dimen>
+ <dimen name="qs_footer_action_button_size">48dp</dimen>
+
+ <dimen name="qs_footer_action_corner_radius">20dp</dimen>
<!-- (48dp - 44dp) / 2 -->
<dimen name="qs_footer_action_inset">2dp</dimen>
@@ -527,25 +529,25 @@
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_corner_radius">14dp</dimen>
- <dimen name="qs_tile_height">96dp</dimen>
+ <dimen name="qs_tile_height">88dp</dimen>
<!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
<dimen name="qs_tile_layout_margin_side">18dp</dimen>
- <dimen name="qs_tile_margin_horizontal">18dp</dimen>
+ <dimen name="qs_tile_margin_horizontal">8dp</dimen>
<dimen name="qs_tile_margin_horizontal_two_line">2dp</dimen>
- <dimen name="qs_tile_margin_vertical">2dp</dimen>
- <dimen name="qs_tile_margin_top_bottom">12dp</dimen>
- <dimen name="qs_tile_margin_top_bottom_negative">-12dp</dimen>
+ <dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen>
+ <dimen name="qs_tile_margin_top_bottom">4dp</dimen>
+ <dimen name="qs_tile_margin_top_bottom_negative">-4dp</dimen>
<!-- The height of the qs customize header. Should be
- (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (0dp)) -
- (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
+ (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) -
+ (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (4dp))
-->
- <dimen name="qs_customize_header_min_height">28dp</dimen>
- <dimen name="qs_tile_margin_top">0dp</dimen>
+ <dimen name="qs_customize_header_min_height">54dp</dimen>
+ <dimen name="qs_tile_margin_top">18dp</dimen>
<dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
- <dimen name="qs_tile_background_size">44dp</dimen>
+ <dimen name="qs_tile_background_size">56dp</dimen>
<dimen name="qs_icon_size">20dp</dimen>
<dimen name="qs_label_container_margin">10dp</dimen>
- <dimen name="qs_quick_tile_size">48dp</dimen>
+ <dimen name="qs_quick_tile_size">60dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
<dimen name="qs_header_tile_margin_bottom">18dp</dimen>
@@ -555,9 +557,9 @@
Scaled @dimen/qs_page_indicator-width by .4f.
-->
<dimen name="qs_page_indicator_dot_width">6.4dp</dimen>
- <dimen name="qs_tile_side_label_padding">6dp</dimen>
+ <dimen name="qs_tile_side_label_padding">12dp</dimen>
<dimen name="qs_tile_icon_size">24dp</dimen>
- <dimen name="qs_tile_text_size">12sp</dimen>
+ <dimen name="qs_tile_text_size">14sp</dimen>
<dimen name="qs_tile_divider_height">1dp</dimen>
<dimen name="qs_panel_padding">16dp</dimen>
<dimen name="qs_dual_tile_height">112dp</dimen>
@@ -568,7 +570,7 @@
<dimen name="qs_tile_padding_bottom">16dp</dimen>
<dimen name="qs_tile_spacing">4dp</dimen>
<dimen name="qs_panel_padding_bottom">0dp</dimen>
- <dimen name="qs_panel_padding_top">@dimen/qs_header_tooltip_height</dimen>
+ <dimen name="qs_panel_padding_top">48dp</dimen>
<dimen name="qs_detail_header_height">56dp</dimen>
<dimen name="qs_detail_header_padding">0dp</dimen>
<dimen name="qs_detail_image_width">56dp</dimen>
@@ -592,7 +594,6 @@
<dimen name="qs_detail_item_icon_width">32dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
- <dimen name="qs_header_tooltip_height">48dp</dimen>
<dimen name="qs_header_alarm_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
<dimen name="qs_header_mobile_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
<dimen name="qs_header_alarm_text_margin_start">6dp</dimen>
@@ -1413,17 +1414,17 @@
<dimen name="accessibility_floating_menu_large_single_radius">33dp</dimen>
<dimen name="accessibility_floating_menu_large_multiple_radius">35dp</dimen>
- <dimen name="rounded_slider_height">44dp</dimen>
+ <dimen name="rounded_slider_height">48dp</dimen>
<!-- rounded_slider_height / 2 -->
- <dimen name="rounded_slider_corner_radius">22dp</dimen>
+ <dimen name="rounded_slider_corner_radius">24dp</dimen>
<dimen name="rounded_slider_icon_size">20dp</dimen>
<!-- (rounded_slider_height - rounded_slider_icon_size) / 2 -->
- <dimen name="rounded_slider_icon_inset">12dp</dimen>
+ <dimen name="rounded_slider_icon_inset">14dp</dimen>
<!-- rounded_slider_corner_radius - rounded_slider_track_corner_radius -->
- <dimen name="rounded_slider_track_inset">18dp</dimen>
- <dimen name="rounded_slider_track_width">8dp</dimen>
+ <dimen name="rounded_slider_track_inset">22dp</dimen>
+ <dimen name="rounded_slider_track_width">4dp</dimen>
<!-- rounded_slider_track_width / 2 -->
- <dimen name="rounded_slider_track_corner_radius">4dp</dimen>
+ <dimen name="rounded_slider_track_corner_radius">2dp</dimen>
<!-- inset for ic_lock_open within a DisabledUdfpsView -->
<dimen name="udfps_unlock_icon_inset">16dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index bbf2048..5827f4e 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -28,8 +28,6 @@
<!-- b/171917882 -->
<bool name="flag_notification_twocolumn">false</bool>
- <bool name="flag_qs_labels">false</bool>
-
<!-- AOD/Lockscreen alternate layout -->
<bool name="flag_keyguard_layout">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4ae1c936..e55142b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2012,7 +2012,7 @@
<string name="notification_menu_settings_action">Settings</string>
<!-- Notification: Snooze panel: Snooze undo button label. [CHAR LIMIT=50]-->
- <string name="snooze_undo">UNDO</string>
+ <string name="snooze_undo">Undo</string>
<!-- Notification: Snooze panel: message indicating how long the notification was snoozed for. [CHAR LIMIT=100]-->
<string name="snoozed_for_time">Snoozed for <xliff:g id="time_amount" example="15 minutes">%1$s</xliff:g></string>
@@ -2953,10 +2953,7 @@
[CHAR LIMIT=NONE] -->
<string name="battery_state_unknown_notification_text">Tap for more information</string>
- <!-- No translation [CHAR LIMIT=0] -->
- <string name="qs_remove_labels" translatable="false"></string>
-
- <string name="qs_tile_label_fontFamily" translatable="false">@*android:string/config_headlineFontFamily</string>
+ <string name="qs_tile_label_fontFamily" translatable="false">@*android:string/config_headlineFontFamilyMedium</string>
<!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] -->
<string name="qs_alarm_tile_no_alarm">No alarm set</string>
diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml
index e386147..68e6ca8 100644
--- a/packages/SystemUI/res/xml/people_space_widget_info.xml
+++ b/packages/SystemUI/res/xml/people_space_widget_info.xml
@@ -26,5 +26,5 @@
android:previewLayout="@layout/people_space_placeholder_layout"
android:resizeMode="horizontal|vertical"
android:configure="com.android.systemui.people.PeopleSpaceActivity"
- android:initialLayout="@layout/people_space_placeholder_layout">
+ android:initialLayout="@layout/people_space_initial_layout">
</appwidget-provider>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index af3239e..1e98f86 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -79,11 +79,6 @@
void startAssistant(in Bundle bundle) = 13;
/**
- * Creates a new gesture monitor
- */
- Bundle monitorGestureInput(String name, int displayId) = 14;
-
- /**
* Notifies that the accessibility button in the system's navigation area has been clicked
*/
void notifyAccessibilityButtonClicked(int displayId) = 15;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java
index 074448d..bf8e6a5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputMonitorCompat.java
@@ -16,10 +16,7 @@
package com.android.systemui.shared.system;
import android.hardware.input.InputManager;
-import android.os.Bundle;
import android.os.Looper;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.view.Choreographer;
import android.view.InputMonitor;
@@ -29,9 +26,8 @@
/**
* @see android.view.InputMonitor
*/
-public class InputMonitorCompat implements Parcelable {
+public class InputMonitorCompat {
private final InputMonitor mInputMonitor;
- private boolean mForReturn = false;
/**
* Monitor input on the specified display for gestures.
@@ -40,10 +36,6 @@
mInputMonitor = InputManager.getInstance().monitorGestureInput(name, displayId);
}
- private InputMonitorCompat(InputMonitor monitor) {
- mInputMonitor = monitor;
- }
-
/**
* @see InputMonitor#pilferPointers()
*/
@@ -66,48 +58,4 @@
return new InputEventReceiver(mInputMonitor.getInputChannel(), looper, choreographer,
listener);
}
-
- /**
- * Gets the input monitor stored in a bundle
- */
- public static InputMonitorCompat fromBundle(Bundle bundle, String key) {
- bundle.setClassLoader(InputMonitorCompat.class.getClassLoader());
- return (InputMonitorCompat) bundle.getParcelable(key);
- }
-
- /**
- * Gets the input monitor compat as the return value.
- */
- public static InputMonitorCompat obtainReturnValue(InputMonitor monitor) {
- final InputMonitorCompat monitorCompat = new InputMonitorCompat(monitor);
- monitorCompat.mForReturn = true;
- return monitorCompat;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- mInputMonitor.writeToParcel(dest,
- mForReturn ? PARCELABLE_WRITE_RETURN_VALUE : flags);
- }
-
- private InputMonitorCompat(Parcel in) {
- mInputMonitor = InputMonitor.CREATOR.createFromParcel(in);
- }
-
- public static final Creator<InputMonitorCompat> CREATOR = new Creator<InputMonitorCompat>() {
- @Override
- public InputMonitorCompat createFromParcel(Parcel in) {
- return new InputMonitorCompat(in);
- }
-
- @Override
- public InputMonitorCompat[] newArray(int size) {
- return new InputMonitorCompat[size];
- }
- };
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 41840af..927bce0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -38,7 +38,6 @@
public class QuickStepContract {
public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
- public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor";
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
// See IPip.aidl
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 032ed7d..f89e365 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -26,14 +26,18 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Color;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.graphics.ColorUtils;
import com.android.keyguard.clock.ClockManager;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -50,6 +54,7 @@
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import java.util.Locale;
@@ -87,6 +92,10 @@
private Executor mUiExecutor;
private SmartspaceSession mSmartspaceSession;
private SmartspaceSession.Callback mSmartspaceCallback;
+ private float mDozeAmount;
+ private int mWallpaperTextColor;
+ private int mDozeColor = Color.WHITE;
+ private ConfigurationController mConfigurationController;
/**
* Listener for changes to the color palette.
@@ -103,8 +112,25 @@
}
};
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onThemeChanged() {
+ updateWallpaperColor();
+ }
+ };
+
private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
+ private final StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ mDozeAmount = eased;
+ updateSmartspaceColor();
+ }
+ };
+
// If set, will replace keyguard_status_area
private BcSmartspaceDataPlugin.SmartspaceView mSmartspaceView;
@@ -121,7 +147,8 @@
PluginManager pluginManager,
FeatureFlags featureFlags,
@Main Executor uiExecutor,
- BatteryController batteryController) {
+ BatteryController batteryController,
+ ConfigurationController configurationController) {
super(keyguardClockSwitch);
mResources = resources;
mStatusBarStateController = statusBarStateController;
@@ -134,6 +161,7 @@
mIsSmartspaceEnabled = featureFlags.isSmartspaceEnabled();
mUiExecutor = uiExecutor;
mBatteryController = batteryController;
+ mConfigurationController = configurationController;
}
/**
@@ -172,6 +200,12 @@
mBatteryController);
mLargeClockViewController.init();
+ mDozeAmount = mStatusBarStateController.getDozeAmount();
+ updateWallpaperColor();
+
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mConfigurationController.addCallback(mConfigurationListener);
+
// If a smartspace plugin is detected, replace the existing smartspace
// (keyguard_status_area), and initialize a new session
mPluginListener = new PluginListener<BcSmartspaceDataPlugin>() {
@@ -186,8 +220,10 @@
mSmartspaceView = plugin.getView(mView);
mSmartspaceView.registerDataProvider(plugin);
+ updateSmartspaceColor();
View asView = (View) mSmartspaceView;
+ // Place plugin view below normal clock...
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
lp.addRule(RelativeLayout.BELOW, R.id.lockscreen_clock_view);
@@ -197,6 +233,11 @@
.getDimensionPixelSize(R.dimen.below_clock_padding_start);
asView.setPadding(padding, 0, padding, 0);
+ // ... but above the large clock
+ lp = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
+ lp.addRule(RelativeLayout.BELOW, asView.getId());
+ mLargeClockFrame.setLayoutParams(lp);
+
View nic = mView.findViewById(
com.android.systemui.R.id.left_aligned_notification_icon_container);
lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
@@ -219,6 +260,7 @@
nic.getLayoutParams();
lp.addRule(RelativeLayout.BELOW, R.id.keyguard_status_area);
nic.setLayoutParams(lp);
+ mLargeClockFrame.setLayoutParams(lp);
mSmartspaceView = null;
}
@@ -235,6 +277,19 @@
mPluginManager.addPluginListener(mPluginListener, BcSmartspaceDataPlugin.class, false);
}
+ private void updateWallpaperColor() {
+ mWallpaperTextColor = Utils.getColorAttrDefaultColor(getContext(),
+ R.attr.wallpaperTextColor);
+ updateSmartspaceColor();
+ }
+
+ private void updateSmartspaceColor() {
+ if (mSmartspaceView != null) {
+ int color = ColorUtils.blendARGB(mWallpaperTextColor, mDozeColor, mDozeAmount);
+ mSmartspaceView.setPrimaryTextColor(color);
+ }
+ }
+
@Override
protected void onViewDetached() {
if (CUSTOM_CLOCKS_ENABLED) {
@@ -249,6 +304,8 @@
mSmartspaceSession = null;
}
mPluginManager.removePluginListener(mPluginListener);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ mConfigurationController.removeCallback(mConfigurationListener);
}
/**
@@ -392,4 +449,9 @@
private int getCurrentLayoutDirection() {
return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
}
+
+ @VisibleForTesting
+ ConfigurationController.ConfigurationListener getConfigurationListener() {
+ return mConfigurationListener;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index 8cd68ef..ab15630 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -18,7 +18,7 @@
val isFaceDisabled: Boolean,
val isBecauseCannotSkipBouncer: Boolean,
val isKeyguardGoingAway: Boolean,
- val isFaceSettingEnabledForUser: Boolean,
+ val isBiometricSettingEnabledForUser: Boolean,
val isLockIconPressed: Boolean,
val isScanningAllowedByStrongAuth: Boolean,
val isPrimaryUser: Boolean,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 67ee1f4..138dd15 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -353,18 +353,15 @@
}
};
- private SparseBooleanArray mFaceSettingEnabledForUser = new SparseBooleanArray();
+ private SparseBooleanArray mBiometricEnabledForUser = new SparseBooleanArray();
private BiometricManager mBiometricManager;
private IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
new IBiometricEnabledOnKeyguardCallback.Stub() {
@Override
- public void onChanged(BiometricSourceType type, boolean enabled, int userId)
- throws RemoteException {
+ public void onChanged(boolean enabled, int userId) throws RemoteException {
mHandler.post(() -> {
- if (type == BiometricSourceType.FACE) {
- mFaceSettingEnabledForUser.put(userId, enabled);
- updateFaceListeningState();
- }
+ mBiometricEnabledForUser.put(userId, enabled);
+ updateBiometricListeningState();
});
}
};
@@ -1119,6 +1116,7 @@
containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
|| containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
final boolean isEncrypted = containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT);
+
return isEncrypted || isLockDown;
}
@@ -1359,7 +1357,7 @@
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:AOD_INTERRUPT_END");
}
- mAuthController.onCancelAodInterrupt();
+ mAuthController.onCancelUdfps();
mIsUdfpsRunningWhileDozing = false;
}
};
@@ -1631,6 +1629,12 @@
mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
}
+ @VisibleForTesting
+ void resetBiometricListeningState() {
+ mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+ mFaceRunningState = BIOMETRIC_STATE_STOPPED;
+ }
+
private void registerRingerTracker() {
mRingerModeTracker.getRingerMode().observeForever(mRingerModeObserver);
}
@@ -1951,7 +1955,7 @@
mIsFaceEnrolled = whitelistIpcs(
() -> mFaceManager != null && mFaceManager.isHardwareDetected()
&& mFaceManager.hasEnrolledTemplates(userId)
- && mFaceSettingEnabledForUser.get(userId));
+ && mBiometricEnabledForUser.get(userId));
}
/**
@@ -2099,7 +2103,7 @@
shouldListenForFingerprintAssistant() || (mKeyguardOccluded && mIsDreaming))
&& !mSwitchingUser && !isFingerprintDisabled(getCurrentUser())
&& (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser
- && allowedOnBouncer;
+ && allowedOnBouncer && mBiometricEnabledForUser.get(getCurrentUser());
return shouldListen;
}
@@ -2158,7 +2162,7 @@
(mBouncer || mAuthInterruptActive || awakeKeyguard
|| shouldListenForFaceAssistant())
&& !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
- && !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed
+ && !mKeyguardGoingAway && mBiometricEnabledForUser.get(user) && !mLockIconPressed
&& strongAuthAllowsScanning && mIsPrimaryUser
&& !mSecureCameraLaunched;
@@ -2176,7 +2180,7 @@
isFaceDisabled(user),
becauseCannotSkipBouncer,
mKeyguardGoingAway,
- mFaceSettingEnabledForUser.get(user),
+ mBiometricEnabledForUser.get(user),
mLockIconPressed,
strongAuthAllowsScanning,
mIsPrimaryUser,
@@ -3235,6 +3239,7 @@
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
+ pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
if (isUdfpsEnrolled()) {
pw.println(" shouldListenForUdfps=" + shouldListenForUdfps());
pw.println(" bouncerVisible=" + mBouncer);
@@ -3257,7 +3262,7 @@
pw.println(" possible=" + isUnlockWithFacePossible(userId));
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
- pw.println(" enabledByUser=" + mFaceSettingEnabledForUser.get(userId));
+ pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
pw.println(" mSecureCameraLaunched=" + mSecureCameraLaunched);
}
if (mFaceListenModels != null && !mFaceListenModels.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index ed8f32f..0c7b55d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -309,18 +309,14 @@
}
/**
- * Cancel a fingerprint scan.
- *
- * The sensor that triggers an AOD interrupt for fingerprint doesn't give
- * ACTION_UP/ACTION_CANCEL events, so the scan needs to be cancelled manually. This should be
- * called when authentication either succeeds or fails. Failing to cancel the scan will leave
- * the screen in high brightness mode.
+ * Cancel a fingerprint scan manually. This will get rid of the white circle on the udfps
+ * sensor area even if the user hasn't explicitly lifted their finger yet.
*/
- public void onCancelAodInterrupt() {
+ public void onCancelUdfps() {
if (mUdfpsController == null) {
return;
}
- mUdfpsController.onCancelAodInterrupt();
+ mUdfpsController.onCancelUdfps();
}
private void sendResultAndCleanUp(@DismissedReason int reason,
@@ -499,6 +495,8 @@
if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
mCurrentDialog.onError(errorMessage);
}
+
+ onCancelUdfps();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index aa818bf..9239a8a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -35,15 +36,23 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
+import android.media.AudioAttributes;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
+import android.view.View;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -94,7 +103,9 @@
@NonNull private final DumpManager mDumpManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
- @NonNull private FalsingManager mFalsingManager;
+ @NonNull private final Vibrator mVibrator;
+ @NonNull private final Handler mMainHandler;
+ @NonNull private final FalsingManager mFalsingManager;
// 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.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -118,6 +129,27 @@
private boolean mIsAodInterruptActive;
@Nullable private Runnable mCancelAodTimeoutAction;
+ private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
+ new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
+
+ private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ private final VibrationEffect mEffectTextureTick =
+ VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
+ private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ private final VibrationEffect mEffectHeavy =
+ VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
+ private final Runnable mAcquiredVibration = new Runnable() {
+ @Override
+ public void run() {
+ String effect = Settings.Global.getString(mContext.getContentResolver(),
+ "udfps_acquired_type");
+ mVibrator.vibrate(getVibration(effect, mEffectTick), VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+ };
+
/**
* Keeps track of state within a single FingerprintService request. Note that this state
* persists across configuration changes, etc, since it is considered a single request.
@@ -227,7 +259,9 @@
};
@SuppressLint("ClickableViewAccessibility")
- private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> {
+ private final UdfpsView.OnTouchListener mOnTouchListener = this::onTouch;
+
+ private boolean onTouch(View view, MotionEvent event) {
UdfpsView udfpsView = (UdfpsView) view;
final boolean isFingerDown = udfpsView.isIlluminationRequested();
boolean handled = false;
@@ -251,6 +285,27 @@
// data for many other pointers because of multi-touch support.
mActivePointerId = event.getPointerId(0);
mVelocityTracker.addMovement(event);
+
+ // TODO: (b/185124905) these settings are for ux testing purposes and should
+ // be removed (or cached) before going into production
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ int startEnabled = Settings.Global.getInt(contentResolver,
+ "udfps_start", 0);
+ if (startEnabled > 0) {
+ String startEffectSetting = Settings.Global.getString(contentResolver,
+ "udfps_start_type");
+ mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick),
+ VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+
+ int acquiredEnabled = Settings.Global.getInt(contentResolver,
+ "udfps_acquired", 0);
+ if (acquiredEnabled > 0) {
+ int delay = Settings.Global.getInt(contentResolver,
+ "udfps_acquired_delay", 500);
+ mMainHandler.removeCallbacks(mAcquiredVibration);
+ mMainHandler.postDelayed(mAcquiredVibration, delay);
+ }
handled = true;
}
break;
@@ -307,7 +362,7 @@
// Do nothing.
}
return handled;
- };
+ }
@Inject
public UdfpsController(@NonNull Context context,
@@ -324,6 +379,9 @@
@NonNull KeyguardViewMediator keyguardViewMediator,
@NonNull FalsingManager falsingManager) {
mContext = context;
+ // TODO (b/185124905): inject main handler and vibrator once done prototyping
+ mMainHandler = new Handler(Looper.getMainLooper());
+ mVibrator = context.getSystemService(Vibrator.class);
mInflater = inflater;
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
// fingerprint manager should never be null.
@@ -559,19 +617,25 @@
// Since the sensor that triggers the AOD interrupt doesn't provide ACTION_UP/ACTION_CANCEL,
// we need to be careful about not letting the screen accidentally remain in high brightness
// mode. As a mitigation, queue a call to cancel the fingerprint scan.
- mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelAodInterrupt,
+ mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps,
AOD_INTERRUPT_TIMEOUT_MILLIS);
// using a hard-coded value for major and minor until it is available from the sensor
onFingerDown(screenX, screenY, minor, major);
}
/**
- * Cancel fingerprint scan.
+ * Cancel updfs scan affordances - ability to hide the HbmSurfaceView (white circle) before
+ * user explicitly lifts their finger. Generally, this should be called whenever udfps fails
+ * or errors.
*
- * This is intended to be called after the fingerprint scan triggered by the AOD interrupt
- * either succeeds or fails.
+ * The sensor that triggers an AOD fingerprint interrupt (see onAodInterrupt) doesn't give
+ * ACTION_UP/ACTION_CANCEL events, so and AOD interrupt scan needs to be cancelled manually.
+ * This should be called when authentication either succeeds or fails. Failing to cancel the
+ * scan will leave the screen in high brightness mode and will show the HbmSurfaceView until
+ * the user lifts their finger.
*/
- void onCancelAodInterrupt() {
+ void onCancelUdfps() {
+ onFingerUp();
if (!mIsAodInterruptActive) {
return;
}
@@ -580,7 +644,6 @@
mCancelAodTimeoutAction = null;
}
mIsAodInterruptActive = false;
- onFingerUp();
}
// This method can be called from the UI thread.
@@ -598,6 +661,7 @@
// This method can be called from the UI thread.
private void onFingerUp() {
+ mMainHandler.removeCallbacks(mAcquiredVibration);
if (mView == null) {
Log.w(TAG, "Null view in onFingerUp");
return;
@@ -617,4 +681,23 @@
// Do nothing. This method can be implemented for devices that require the high-brightness
// mode for fingerprint illumination.
}
+
+ private VibrationEffect getVibration(String effect, VibrationEffect defaultEffect) {
+ if (TextUtils.isEmpty(effect)) {
+ return defaultEffect;
+ }
+
+ switch (effect.toLowerCase()) {
+ case "click":
+ return mEffectClick;
+ case "heavy":
+ return mEffectHeavy;
+ case "texture_tick":
+ return mEffectTextureTick;
+ case "tick":
+ return mEffectTick;
+ default:
+ return defaultEffect;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 1e86cf1..9d47bbb 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -121,6 +121,7 @@
params.setFitInsetsTypes(0 /* ignore all system bar insets */);
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ params.setTrustedOverlay();
if (looper == null) {
// Use Looper.myLooper() if looper is not specified.
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index ce5795c..767d7ab 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -35,12 +35,10 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.GlobalActions;
-import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
@@ -50,18 +48,17 @@
public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
private final Context mContext;
- private final Lazy<GlobalActionsDialog> mGlobalActionsDialogLazy;
+ private final Lazy<GlobalActionsDialogLite> mGlobalActionsDialogLazy;
private final KeyguardStateController mKeyguardStateController;
private final DeviceProvisionedController mDeviceProvisionedController;
- private final ExtensionController.Extension<GlobalActionsPanelPlugin> mWalletPluginProvider;
private final BlurUtils mBlurUtils;
private final CommandQueue mCommandQueue;
- private GlobalActionsDialog mGlobalActionsDialog;
+ private GlobalActionsDialogLite mGlobalActionsDialog;
private boolean mDisabled;
@Inject
public GlobalActionsImpl(Context context, CommandQueue commandQueue,
- Lazy<GlobalActionsDialog> globalActionsDialogLazy, BlurUtils blurUtils) {
+ Lazy<GlobalActionsDialogLite> globalActionsDialogLazy, BlurUtils blurUtils) {
mContext = context;
mGlobalActionsDialogLazy = globalActionsDialogLazy;
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
@@ -69,10 +66,6 @@
mCommandQueue = commandQueue;
mBlurUtils = blurUtils;
mCommandQueue.addCallback(this);
- mWalletPluginProvider = Dependency.get(ExtensionController.class)
- .newExtension(GlobalActionsPanelPlugin.class)
- .withPlugin(GlobalActionsPanelPlugin.class)
- .build();
}
@Override
@@ -89,8 +82,7 @@
if (mDisabled) return;
mGlobalActionsDialog = mGlobalActionsDialogLazy.get();
mGlobalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(),
- mDeviceProvisionedController.isDeviceProvisioned(),
- mWalletPluginProvider.get());
+ mDeviceProvisionedController.isDeviceProvisioned());
Dependency.get(KeyguardUpdateMonitor.class).requestFaceAuth();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index be9d6bd6..56375ad 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -70,7 +70,6 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
@@ -160,7 +159,7 @@
*/
public class NavigationBar implements View.OnAttachStateChangeListener,
Callbacks, NavigationModeController.ModeChangedListener,
- AccessibilityButtonModeObserver.ModeChangedListener, DisplayManager.DisplayListener {
+ AccessibilityButtonModeObserver.ModeChangedListener {
public static final String TAG = "NavigationBar";
private static final boolean DEBUG = false;
@@ -660,7 +659,6 @@
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
if (mOrientationHandle != null) {
resetSecondaryHandle();
- mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
mWindowManager.removeView(mOrientationHandle);
mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener(
@@ -699,7 +697,15 @@
mLayoutDirection = ld;
refreshLayout(ld);
}
+
repositionNavigationBar();
+ if (canShowSecondaryHandle()) {
+ int rotation = newConfig.windowConfiguration.getRotation();
+ if (rotation != mCurrentRotation) {
+ mCurrentRotation = rotation;
+ orientSecondaryHomeHandle();
+ }
+ }
}
private void initSecondaryHomeHandleForRotation() {
@@ -707,9 +713,6 @@
return;
}
- mContext.getSystemService(DisplayManager.class)
- .registerDisplayListener(this, new Handler(Looper.getMainLooper()));
-
mOrientationHandle = new QuickswitchOrientedNavHandle(mContext);
mOrientationHandle.setId(R.id.secondary_home_handle);
@@ -1604,30 +1607,6 @@
private final AccessibilityServicesStateChangeListener mAccessibilityListener =
this::updateAccessibilityServicesState;
- @Override
- public void onDisplayAdded(int displayId) {
-
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
-
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- if (!canShowSecondaryHandle()) {
- return;
- }
-
- int rotation = mContext.getResources().getConfiguration()
- .windowConfiguration.getRotation();
- if (rotation != mCurrentRotation) {
- mCurrentRotation = rotation;
- orientSecondaryHomeHandle();
- }
- }
-
private boolean canShowSecondaryHandle() {
return mNavBarMode == NAV_BAR_MODE_GESTURAL && mOrientationHandle != null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 6d1109e..3544f60 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -17,14 +17,18 @@
package com.android.systemui.navigationbar;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -80,6 +84,8 @@
ConfigurationController.ConfigurationListener,
NavigationModeController.ModeChangedListener, Dumpable {
+ private static final float TABLET_MIN_DPS = 600;
+
private static final String TAG = NavigationBarController.class.getSimpleName();
private final Context mContext;
@@ -107,6 +113,8 @@
private final Handler mHandler;
private final DisplayManager mDisplayManager;
private final NavigationBarOverlayController mNavBarOverlayController;
+ private int mNavMode;
+ private boolean mIsTablet;
/** A displayId - nav bar maps. */
@VisibleForTesting
@@ -172,11 +180,30 @@
configurationController.addCallback(this);
mConfigChanges.applyNewConfig(mContext.getResources());
mNavBarOverlayController = navBarOverlayController;
+ mNavMode = mNavigationModeController.addListener(this);
mNavigationModeController.addListener(this);
}
@Override
public void onConfigChanged(Configuration newConfig) {
+ boolean isOldConfigTablet = mIsTablet;
+ mIsTablet = isTablet(newConfig);
+ boolean largeScreenChanged = mIsTablet != isOldConfigTablet;
+ // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded
+ if (isThreeButtonTaskbarFlagEnabled() &&
+ largeScreenChanged && mNavMode == NAV_BAR_MODE_3BUTTON) {
+ if (!mIsTablet) {
+ // Folded state, show 3 button nav bar
+ createNavigationBar(mContext.getDisplay(), null, null);
+ } else {
+ // Unfolded state, hide 3 button nav bars
+ for (int i = 0; i < mNavigationBars.size(); i++) {
+ removeNavigationBar(mNavigationBars.keyAt(i));
+ }
+ }
+ return;
+ }
+
if (mConfigChanges.applyNewConfig(mContext.getResources())) {
for (int i = 0; i < mNavigationBars.size(); i++) {
recreateNavigationBar(mNavigationBars.keyAt(i));
@@ -190,7 +217,19 @@
@Override
public void onNavigationModeChanged(int mode) {
+ final int oldMode = mNavMode;
+ mNavMode = mode;
mHandler.post(() -> {
+ // create/destroy nav bar based on nav mode only in unfolded state
+ if (isThreeButtonTaskbarFlagEnabled() && oldMode != mNavMode && mIsTablet) {
+ if (oldMode == NAV_BAR_MODE_3BUTTON &&
+ mNavigationBars.get(mContext.getDisplayId()) == null) {
+ // We remove navbar for 3 button unfolded, add it back in
+ createNavigationBar(mContext.getDisplay(), null, null);
+ } else if (mNavMode == NAV_BAR_MODE_3BUTTON) {
+ removeNavigationBar(mContext.getDisplayId());
+ }
+ }
for (int i = 0; i < mNavigationBars.size(); i++) {
NavigationBar navBar = mNavigationBars.valueAt(i);
if (navBar == null) {
@@ -212,6 +251,7 @@
@Override
public void onDisplayReady(int displayId) {
Display display = mDisplayManager.getDisplay(displayId);
+ mIsTablet = isTablet(mContext.getResources().getConfiguration());
createNavigationBar(display, null /* savedState */, null /* result */);
}
@@ -267,6 +307,10 @@
return;
}
+ if (isThreeButtonTaskbarEnabled()) {
+ return;
+ }
+
final int displayId = display.getDisplayId();
final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
@@ -398,6 +442,24 @@
return mNavigationBars.get(DEFAULT_DISPLAY);
}
+ private boolean isThreeButtonTaskbarEnabled() {
+ return mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON &&
+ isThreeButtonTaskbarFlagEnabled();
+ }
+
+ private boolean isThreeButtonTaskbarFlagEnabled() {
+ return SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
+ }
+
+ private boolean isTablet(Configuration newConfig) {
+ float density = Resources.getSystem().getDisplayMetrics().density;
+ int size = Math.min((int) (density * newConfig.screenWidthDp),
+ (int) (density* newConfig.screenHeightDp));
+ DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
+ float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+ return (size / densityRatio) >= TABLET_MIN_DPS;
+ }
+
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
for (int i = 0; i < mNavigationBars.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index a8c4d6e..01c80f6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -281,7 +281,7 @@
// When in gestural and the IME is showing, don't use the nearest region since it will take
// gesture space away from the IME
info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- info.touchableRegion.set(getButtonLocations(false /* includeFloatingRotationButton */,
+ info.touchableRegion.set(getButtonLocations(false /* includeFloatingButtons */,
false /* inScreen */, false /* useNearestRegion */));
};
@@ -982,7 +982,7 @@
*/
public void notifyActiveTouchRegions() {
mOverviewProxyService.onActiveNavBarRegionChanges(
- getButtonLocations(true /* includeFloatingRotationButton */, true /* inScreen */,
+ getButtonLocations(true /* includeFloatingButtons */, true /* inScreen */,
true /* useNearestRegion */));
}
@@ -995,14 +995,14 @@
}
/**
- * @param includeFloatingRotationButton Whether to include the floating rotation button in the
- * region for all the buttons
+ * @param includeFloatingButtons Whether to include the floating rotation and overlay button in
+ * the region for all the buttons
* @param inScreenSpace Whether to return values in screen space or window space
* @param useNearestRegion Whether to use the nearest region instead of the actual button bounds
* @return
*/
- private Region getButtonLocations(boolean includeFloatingRotationButton,
- boolean inScreenSpace, boolean useNearestRegion) {
+ private Region getButtonLocations(boolean includeFloatingButtons, boolean inScreenSpace,
+ boolean useNearestRegion) {
if (useNearestRegion && !inScreenSpace) {
// We currently don't support getting the nearest region in anything but screen space
useNearestRegion = false;
@@ -1014,13 +1014,13 @@
updateButtonLocation(getRecentsButton(), inScreenSpace, useNearestRegion);
updateButtonLocation(getImeSwitchButton(), inScreenSpace, useNearestRegion);
updateButtonLocation(getAccessibilityButton(), inScreenSpace, useNearestRegion);
- if (includeFloatingRotationButton && mFloatingRotationButton.isVisible()) {
+ if (includeFloatingButtons && mFloatingRotationButton.isVisible()) {
// Note: this button is floating so the nearest region doesn't apply
updateButtonLocation(mFloatingRotationButton.getCurrentView(), inScreenSpace);
} else {
updateButtonLocation(getRotateSuggestionButton(), inScreenSpace, useNearestRegion);
}
- if (mNavBarOverlayController.isNavigationBarOverlayEnabled()
+ if (includeFloatingButtons && mNavBarOverlayController.isNavigationBarOverlayEnabled()
&& mNavBarOverlayController.isVisible()) {
// Note: this button is floating so the nearest region doesn't apply
updateButtonLocation(mNavBarOverlayController.getCurrentView(), inScreenSpace);
@@ -1186,6 +1186,7 @@
boolean uiCarModeChanged = updateCarMode();
updateIcons(mTmpLastConfiguration);
updateRecentsIcon();
+ mEdgeBackGestureHandler.onConfigurationChanged(mConfiguration);
mRecentsOnboarding.onConfigurationChanged(mConfiguration);
if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
|| mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index b6a800f..806ea4f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -50,6 +51,7 @@
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.view.WindowMetrics;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
@@ -86,8 +88,8 @@
/**
* Utility class to handle edge swipes for back gesture
*/
-public class EdgeBackGestureHandler extends CurrentUserTracker implements DisplayListener,
- PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> {
+public class EdgeBackGestureHandler extends CurrentUserTracker
+ implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> {
private static final String TAG = "EdgeBackGestureHandler";
private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
@@ -123,7 +125,7 @@
@Override
public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
mStartingQuickstepRotation = rotation;
- updateDisabledForQuickstep();
+ updateDisabledForQuickstep(mContext.getResources().getConfiguration());
}
};
@@ -414,7 +416,6 @@
if (!mIsEnabled) {
mGestureNavigationSettingsObserver.unregister();
- mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Unregister display listener");
}
@@ -433,8 +434,6 @@
} else {
mGestureNavigationSettingsObserver.register();
updateDisplaySize();
- mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
- mContext.getMainThreadHandler());
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Register display listener");
}
@@ -805,35 +804,28 @@
Dependency.get(ProtoTracer.class).scheduleFrameUpdate();
}
- private void updateDisabledForQuickstep() {
- int rotation = mContext.getResources().getConfiguration().windowConfiguration.getRotation();
+ private void updateDisabledForQuickstep(Configuration newConfig) {
+ int rotation = newConfig.windowConfiguration.getRotation();
mDisabledForQuickstep = mStartingQuickstepRotation > -1 &&
mStartingQuickstepRotation != rotation;
}
- @Override
- public void onDisplayAdded(int displayId) { }
-
- @Override
- public void onDisplayRemoved(int displayId) { }
-
- @Override
- public void onDisplayChanged(int displayId) {
+ public void onConfigurationChanged(Configuration newConfig) {
if (mStartingQuickstepRotation > -1) {
- updateDisabledForQuickstep();
+ updateDisabledForQuickstep(newConfig);
}
if (DEBUG_MISSING_GESTURE) {
- Log.d(DEBUG_MISSING_GESTURE_TAG, "Display changed: mDisplayId=" + mDisplayId
- + " displayId=" + displayId);
+ Log.d(DEBUG_MISSING_GESTURE_TAG, "Config changed: config=" + newConfig);
}
- if (displayId == mDisplayId) {
- updateDisplaySize();
- }
+ updateDisplaySize();
}
private void updateDisplaySize() {
- mContext.getDisplay().getRealSize(mDisplaySize);
+ WindowMetrics metrics = mContext.getSystemService(WindowManager.class)
+ .getMaximumWindowMetrics();
+ Rect bounds = metrics.getBounds();
+ mDisplaySize.set(bounds.width(), bounds.height());
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Update display size: mDisplaySize=" + mDisplaySize);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 32723b4..f7fa5bf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -8,7 +8,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
@@ -71,8 +70,6 @@
private int mMinRows = 1;
private int mMaxColumns = TileLayout.NO_MAX_COLUMNS;
- private final boolean mSideLabels;
-
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context, SCROLL_CUBIC);
@@ -83,14 +80,9 @@
mLayoutDirection = getLayoutDirection();
mClippingRect = new Rect();
- TypedArray t = context.getTheme().obtainStyledAttributes(
- attrs, R.styleable.PagedTileLayout, 0, 0);
- mSideLabels = t.getBoolean(R.styleable.PagedTileLayout_sideLabels, false);
- t.recycle();
- if (mSideLabels) {
- setPageMargin(context.getResources().getDimensionPixelOffset(
+ // Make sure there's a space between pages when scroling
+ setPageMargin(context.getResources().getDimensionPixelOffset(
R.dimen.qs_tile_margin_horizontal));
- }
}
private int mLastMaxHeight = -1;
@@ -228,8 +220,7 @@
private TileLayout createTileLayout() {
TileLayout page = (TileLayout) LayoutInflater.from(getContext())
- .inflate(mSideLabels ? R.layout.qs_paged_page_side_labels
- : R.layout.qs_paged_page, this, false);
+ .inflate(R.layout.qs_paged_page, this, false);
page.setMinRows(mMinRows);
page.setMaxColumns(mMaxColumns);
return page;
@@ -345,9 +336,8 @@
// Update bottom padding, useful for removing extra space once the panel page indicator is
// hidden.
Resources res = getContext().getResources();
- if (mSideLabels) {
- setPageMargin(res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal));
- }
+ setPageMargin(res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal));
+
setPadding(0, 0, 0,
getContext().getResources().getDimensionPixelSize(
R.dimen.qs_paged_tile_layout_padding_bottom));
@@ -550,18 +540,6 @@
}
};
- public static class TilePage extends TileLayout {
-
- public TilePage(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public boolean isFull() {
- return mRecords.size() >= maxTiles();
- }
-
- }
-
private final PagerAdapter mAdapter = new PagerAdapter() {
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index ea471b9..cefcd4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -33,7 +33,6 @@
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.tileimpl.HeightOverrideable;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -102,14 +101,13 @@
private final Executor mExecutor;
private final TunerService mTunerService;
private boolean mShowCollapsedOnKeyguard;
- private final FeatureFlags mFeatureFlags;
@Inject
public QSAnimator(QS qs, QuickQSPanel quickPanel, QuickStatusBarHeader quickStatusBarHeader,
QSPanelController qsPanelController,
QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
QSSecurityFooter securityFooter, @Main Executor executor, TunerService tunerService,
- FeatureFlags featureFlags, QSExpansionPathInterpolator qsExpansionPathInterpolator) {
+ QSExpansionPathInterpolator qsExpansionPathInterpolator) {
mQs = qs;
mQuickQsPanel = quickPanel;
mQsPanelController = qsPanelController;
@@ -119,7 +117,6 @@
mHost = qsTileHost;
mExecutor = executor;
mTunerService = tunerService;
- mFeatureFlags = featureFlags;
mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
mHost.addCallback(this);
mQsPanelController.addOnAttachStateChangeListener(this);
@@ -247,7 +244,6 @@
+ mQs.getHeader().getPaddingBottom();
firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
- boolean qsSideLabelsEnabled = mFeatureFlags.isQSLabelsEnabled();
int qqsTileHeight = 0;
if (mQsPanelController.areThereTiles()) {
@@ -275,22 +271,19 @@
if (count < tileLayout.getNumVisibleTiles()) {
getRelativePosition(loc1, quickTileView, view);
getRelativePosition(loc2, tileView, view);
- int yOffset = qsSideLabelsEnabled
- ? loc2[1] - loc1[1]
- : mQuickStatusBarHeader.getOffsetTranslation();
+ int yOffset = loc2[1] - loc1[1];
// Move the quick tile right from its location to the new one.
- View v = qsSideLabelsEnabled ? quickTileView.getIcon() : quickTileView;
+ View v = quickTileView.getIcon();
translationXBuilder.addFloat(v, "translationX", 0, xDiff);
translationYBuilder.addFloat(v, "translationY", 0, yDiff - yOffset);
mAllViews.add(v);
// Move the real tile from the quick tile position to its final
// location.
- v = qsSideLabelsEnabled ? tileIcon : tileView;
+ v = tileIcon;
translationXBuilder.addFloat(v, "translationX", -xDiff, 0);
translationYBuilder.addFloat(v, "translationY", -yDiff + yOffset, 0);
- if (qsSideLabelsEnabled) {
// Offset the translation animation on the views
// (that goes from 0 to getOffsetTranslation)
int offsetWithQSBHTranslation =
@@ -300,28 +293,24 @@
translationYBuilder.addFloat(tileView, "translationY",
-offsetWithQSBHTranslation, 0);
- if (mQQSTileHeightAnimator == null) {
- mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
- quickTileView.getHeight(), tileView.getHeight());
- qqsTileHeight = quickTileView.getHeight();
- }
-
- mQQSTileHeightAnimator.addView(quickTileView);
- View qqsLabelContainer = quickTileView.getLabelContainer();
- View qsLabelContainer = tileView.getLabelContainer();
-
- getRelativePosition(loc1, qqsLabelContainer, view);
- getRelativePosition(loc2, qsLabelContainer, view);
- yDiff = loc2[1] - loc1[1] - yOffset;
-
- translationYBuilder.addFloat(qqsLabelContainer, "translationY", 0,
- yDiff);
- translationYBuilder.addFloat(qsLabelContainer, "translationY", -yDiff,
- 0);
- mAllViews.add(qqsLabelContainer);
- mAllViews.add(qsLabelContainer);
+ if (mQQSTileHeightAnimator == null) {
+ mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
+ quickTileView.getHeight(), tileView.getHeight());
+ qqsTileHeight = quickTileView.getHeight();
}
+ mQQSTileHeightAnimator.addView(quickTileView);
+ View qqsLabelContainer = quickTileView.getLabelContainer();
+ View qsLabelContainer = tileView.getLabelContainer();
+
+ getRelativePosition(loc1, qqsLabelContainer, view);
+ getRelativePosition(loc2, qsLabelContainer, view);
+ yDiff = loc2[1] - loc1[1] - yOffset;
+
+ translationYBuilder.addFloat(qqsLabelContainer, "translationY", 0, yDiff);
+ translationYBuilder.addFloat(qsLabelContainer, "translationY", -yDiff, 0);
+ mAllViews.add(qqsLabelContainer);
+ mAllViews.add(qsLabelContainer);
} else { // These tiles disappear when expanding
firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0);
translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
@@ -333,11 +322,7 @@
translationX);
}
- if (qsSideLabelsEnabled) {
- mQuickQsViews.add(tileView);
- } else {
- mQuickQsViews.add(tileView.getIconWithBackground());
- }
+ mQuickQsViews.add(tileView);
mAllViews.add(tileView.getIcon());
mAllViews.add(quickTileView);
} else if (mFullRows && isIconInAnimatedRow(count)) {
@@ -346,27 +331,22 @@
mAllViews.add(tileIcon);
} else {
- if (!qsSideLabelsEnabled) {
- firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
- firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
- } else {
- // Pretend there's a corresponding QQS tile (for the position) that we are
- // expanding from.
- SideLabelTileLayout qqsLayout =
- (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
- getRelativePosition(loc1, qqsLayout, view);
- getRelativePosition(loc2, tileView, view);
- int diff = loc2[1] - (loc1[1] + qqsLayout.getPhantomTopPosition(count));
- translationYBuilder.addFloat(tileView, "translationY", -diff, 0);
- if (mOtherTilesExpandAnimator == null) {
- mOtherTilesExpandAnimator =
- new HeightExpansionAnimator(
- this, qqsTileHeight, tileView.getHeight());
- }
- mOtherTilesExpandAnimator.addView(tileView);
- tileView.setClipChildren(true);
- tileView.setClipToPadding(true);
+ // Pretend there's a corresponding QQS tile (for the position) that we are
+ // expanding from.
+ SideLabelTileLayout qqsLayout =
+ (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
+ getRelativePosition(loc1, qqsLayout, view);
+ getRelativePosition(loc2, tileView, view);
+ int diff = loc2[1] - (loc1[1] + qqsLayout.getPhantomTopPosition(count));
+ translationYBuilder.addFloat(tileView, "translationY", -diff, 0);
+ if (mOtherTilesExpandAnimator == null) {
+ mOtherTilesExpandAnimator =
+ new HeightExpansionAnimator(
+ this, qqsTileHeight, tileView.getHeight());
}
+ mOtherTilesExpandAnimator.addView(tileView);
+ tileView.setClipChildren(true);
+ tileView.setClipToPadding(true);
}
mAllViews.add(tileView);
@@ -392,7 +372,6 @@
.build();
// Fade in the tiles/labels as we reach the final position.
Builder builder = new Builder()
- .setStartDelay(qsSideLabelsEnabled ? 0 : EXPANDED_TILE_DELAY)
.addFloat(tileLayout, "alpha", 0, 1);
mFirstPageDelayedAnimator = builder.build();
@@ -470,12 +449,7 @@
// Returns true if the view is a possible page in PagedTileLayout
private boolean isAPage(View view) {
- if (view instanceof PagedTileLayout.TilePage) {
- return true;
- } else if (view instanceof SideLabelTileLayout) {
- return !(view instanceof QuickQSPanel.QQSSideLabelTileLayout);
- }
- return false;
+ return view.getClass().equals(SideLabelTileLayout.class);
}
public void setPosition(float position) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 586176f..bf9acc2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -22,7 +22,6 @@
import android.content.res.Configuration;
import android.graphics.Point;
import android.util.AttributeSet;
-import android.util.Pair;
import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
@@ -61,7 +60,6 @@
private QuickStatusBarHeader mHeader;
private float mQsExpansion;
private QSCustomizer mQSCustomizer;
- private View mDragHandle;
private NonInterceptingScrollView mQSPanelContainer;
private View mBackground;
@@ -84,7 +82,6 @@
mQSDetail = findViewById(R.id.qs_detail);
mHeader = findViewById(R.id.header);
mQSCustomizer = findViewById(R.id.qs_customize);
- mDragHandle = findViewById(R.id.qs_drag_handle_view);
mBackground = findViewById(R.id.quick_settings_background);
mHeader.getHeaderQsPanel().setMediaVisibilityChangedListener((visible) -> {
if (mHeader.getHeaderQsPanel().isShown()) {
@@ -240,8 +237,6 @@
int scrollBottom = calculateContainerBottom();
setBottom(getTop() + height);
mQSDetail.setBottom(getTop() + scrollBottom);
- // Pin the drag handle to the bottom of the panel.
- mDragHandle.setTranslationY(scrollBottom - mDragHandle.getHeight());
mBackground.setTop(mQSPanelContainer.getTop());
updateBackgroundBottom(scrollBottom, animate);
}
@@ -278,7 +273,6 @@
public void setExpansion(float expansion) {
mQsExpansion = expansion;
- mDragHandle.setAlpha(1.0f - expansion);
updateExpansion();
}
@@ -296,9 +290,6 @@
if (view == mQSPanelContainer) {
// QS panel lays out some of its content full width
qsPanelController.setContentMargins(mContentPadding, mContentPadding);
- Pair<Integer, Integer> margins = qsPanelController.getVisualSideMargins();
- // Apply paddings based on QSPanel
- mQSCustomizer.setContentPaddings(margins.first, margins.second);
} else if (view == mHeader) {
// The header contains the QQS panel which needs to have special padding, to
// visually align them.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index eb7b115..3718713 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -71,7 +71,6 @@
private float mExpansionAmount;
protected View mEdit;
- protected View mEditContainer;
private TouchAnimator mSettingsCogAnimator;
private View mActionsContainer;
@@ -107,7 +106,6 @@
mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
mActionsContainer = requireViewById(R.id.qs_footer_actions_container);
- mEditContainer = findViewById(R.id.qs_footer_actions_edit_container);
mBuildText = findViewById(R.id.build);
mTunerIcon = requireViewById(R.id.tuner_icon);
@@ -185,9 +183,6 @@
.addFloat(mPageIndicator, "alpha", 0, 1)
.addFloat(mBuildText, "alpha", 0, 1)
.setStartDelay(0.9f);
- if (mEditContainer != null) {
- builder.addFloat(mEditContainer, "alpha", 0, 1);
- }
return builder.build();
}
@@ -283,9 +278,6 @@
mTunerIcon.setVisibility(isTunerEnabled ? View.VISIBLE : View.INVISIBLE);
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.GONE);
- if (mEditContainer != null) {
- mEditContainer.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
- }
mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 27cc268..f89e70a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -27,12 +27,10 @@
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
-import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewStub;
import android.widget.LinearLayout;
import com.android.internal.logging.UiEventLogger;
@@ -72,8 +70,6 @@
private final H mHandler = new H();
/** Whether or not the QS media player feature is enabled. */
protected boolean mUsingMediaPlayer;
- private int mVisualMarginStart;
- private int mVisualMarginEnd;
protected boolean mExpanded;
protected boolean mListening;
@@ -96,7 +92,6 @@
private PageIndicator mFooterPageIndicator;
private int mContentMarginStart;
private int mContentMarginEnd;
- private int mVisualTilePadding;
private boolean mUsingHorizontalLayout;
private Record mDetailRecord;
@@ -111,9 +106,7 @@
protected QSTileLayout mTileLayout;
private int mLastOrientation = -1;
private int mMediaTotalBottomMargin;
- private int mFooterMarginStartHorizontal;
private Consumer<Boolean> mMediaVisibilityChangedListener;
- protected boolean mSideLabels;
public QSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -128,21 +121,7 @@
}
- protected void inflateQSFooter(boolean newFooter) {
- ViewStub stub = findViewById(R.id.qs_footer_stub);
- if (stub != null) {
- stub.setLayoutResource(
- newFooter ? R.layout.qs_footer_impl_two_lines : R.layout.qs_footer_impl);
- stub.inflate();
- mFooter = findViewById(R.id.qs_footer);
- }
- }
-
- void initialize(boolean sideLabels) {
- mSideLabels = sideLabels;
-
- inflateQSFooter(sideLabels);
-
+ void initialize() {
mRegularTileLayout = createRegularTileLayout();
mTileLayout = mRegularTileLayout;
@@ -195,8 +174,7 @@
public QSTileLayout createRegularTileLayout() {
if (mRegularTileLayout == null) {
mRegularTileLayout = (QSTileLayout) LayoutInflater.from(mContext)
- .inflate(mSideLabels ? R.layout.qs_paged_tile_layout_side_labels
- : R.layout.qs_paged_tile_layout, this, false);
+ .inflate(R.layout.qs_paged_tile_layout, this, false);
}
return mRegularTileLayout;
}
@@ -311,11 +289,6 @@
}
public void updateResources() {
- int tileSize = getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
- int tileBg = getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size);
- mFooterMarginStartHorizontal = getResources().getDimensionPixelSize(
- R.dimen.qs_footer_horizontal_margin);
- mVisualTilePadding = mSideLabels ? 0 : (int) ((tileSize - tileBg) / 2.0f);
updatePadding();
updatePageIndicator();
@@ -358,6 +331,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mFooter = findViewById(R.id.qs_footer);
mDivider = findViewById(R.id.divider);
}
@@ -638,60 +612,10 @@
// to the edge like the brightness slider
mContentMarginStart = startMargin;
mContentMarginEnd = endMargin;
- updateTileLayoutMargins(mContentMarginStart - mVisualTilePadding,
- mContentMarginEnd - mVisualTilePadding);
updateMediaHostContentMargins(mediaHostView);
- updateFooterMargin();
updateDividerMargin();
}
- private void updateFooterMargin() {
- if (mFooter != null) {
- int footerMargin = 0;
- int indicatorMargin = 0;
- if (mUsingHorizontalLayout && !mSideLabels) {
- footerMargin = mFooterMarginStartHorizontal;
- indicatorMargin = footerMargin - mVisualMarginEnd;
- }
- updateMargins(mFooter, footerMargin, 0);
- // The page indicator isn't centered anymore because of the visual positioning.
- // Let's fix it by adding some margin
- if (mFooterPageIndicator != null) {
- updateMargins(mFooterPageIndicator, 0, indicatorMargin);
- }
- }
- }
-
- /**
- * Update the margins of all tile Layouts.
- *
- * @param visualMarginStart the visual start margin of the tile, adjusted for local insets
- * to the tile. This can be set on a tileLayout
- * @param visualMarginEnd the visual end margin of the tile, adjusted for local insets
- * to the tile. This can be set on a tileLayout
- */
- private void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
- mVisualMarginStart = visualMarginStart;
- mVisualMarginEnd = visualMarginEnd;
- updateTileLayoutMargins();
- }
-
- public Pair<Integer, Integer> getVisualSideMargins() {
- if (mSideLabels) {
- return new Pair(0, 0);
- } else {
- return new Pair(mVisualMarginStart, mUsingHorizontalLayout ? 0 : mVisualMarginEnd);
- }
- }
-
- private void updateTileLayoutMargins() {
- int marginEnd = mVisualMarginEnd;
- if (mUsingHorizontalLayout || mSideLabels) {
- marginEnd = 0;
- }
- updateMargins((View) mTileLayout, mSideLabels ? 0 : mVisualMarginStart, marginEnd);
- }
-
private void updateDividerMargin() {
if (mDivider == null) return;
updateMargins(mDivider, mContentMarginStart, mContentMarginEnd);
@@ -769,22 +693,13 @@
newLayout.setListening(mListening, uiEventLogger);
if (needsDynamicRowsAndColumns()) {
newLayout.setMinRows(horizontal ? 2 : 1);
- // Let's use 3 columns to match the current layout
- int columns;
- if (mSideLabels) {
- columns = horizontal ? 2 : 4;
- } else {
- columns = horizontal ? 3 : TileLayout.NO_MAX_COLUMNS;
- }
- newLayout.setMaxColumns(columns);
+ newLayout.setMaxColumns(horizontal ? 2 : 4);
}
updateMargins(mediaHostView);
}
}
private void updateMargins(ViewGroup mediaHostView) {
- updateTileLayoutMargins();
- updateFooterMargin();
updateDividerMargin();
updateMediaHostContentMargins(mediaHostView);
updateHorizontalLinearLayoutMargins();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index eda1abb..5b6b5df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -22,7 +22,6 @@
import android.annotation.NonNull;
import android.content.res.Configuration;
-import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
@@ -291,11 +290,6 @@
}
/** */
- public Pair<Integer, Integer> getVisualSideMargins() {
- return mView.getVisualSideMargins();
- }
-
- /** */
public void showDetailAdapter(DetailAdapter detailAdapter, int x, int y) {
mView.showDetailAdapter(true, detailAdapter, new int[]{x, y});
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index e41a038..925c9eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -75,8 +75,6 @@
private float mRevealExpansion;
private final QSHost.Callback mQSHostCallback = this::setTiles;
- protected boolean mShowLabels = true;
- protected boolean mQSLabelFlag;
private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
new QSPanel.OnConfigurationChangedListener() {
@@ -121,14 +119,13 @@
mQSLogger = qsLogger;
mDumpManager = dumpManager;
mFeatureFlags = featureFlags;
- mQSLabelFlag = featureFlags.isQSLabelsEnabled();
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources());
}
@Override
protected void onInit() {
- mView.initialize(mQSLabelFlag);
+ mView.initialize();
mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), "");
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index e7828c3..63733b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -50,16 +50,11 @@
}
@Override
- void initialize(boolean sideLabels) {
- super.initialize(sideLabels);
+ void initialize() {
+ super.initialize();
applyBottomMargin((View) mRegularTileLayout);
}
- @Override
- protected void inflateQSFooter(boolean newFooter) {
- // No footer
- }
-
private void applyBottomMargin(View view) {
int margin = getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_bottom);
MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
@@ -74,22 +69,14 @@
@Override
public TileLayout createRegularTileLayout() {
- if (mSideLabels) {
- return new QQSSideLabelTileLayout(mContext);
- } else {
- return new QuickQSPanel.HeaderTileLayout(mContext);
- }
+ return new QQSSideLabelTileLayout(mContext);
}
@Override
protected QSTileLayout createHorizontalTileLayout() {
- if (mSideLabels) {
- TileLayout t = createRegularTileLayout();
- t.setMaxColumns(2);
- return t;
- } else {
- return new DoubleLineTileLayout(mContext);
- }
+ TileLayout t = createRegularTileLayout();
+ t.setMaxColumns(2);
+ return t;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 30a08c6..7518b20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -141,19 +141,6 @@
}
}
- /**
- * Sets the padding for the RecyclerView. Also, updates the margin between the tiles in the
- * {@link TileAdapter}.
- */
- public void setContentPaddings(int paddingStart, int paddingEnd) {
- mRecyclerView.setPaddingRelative(
- paddingStart,
- mRecyclerView.getPaddingTop(),
- paddingEnd,
- mRecyclerView.getPaddingBottom()
- );
- }
-
/** Hide the customizer. */
public void hide(boolean animate) {
if (isShown) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 006b230..5080533 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,8 +14,6 @@
package com.android.systemui.qs.customize;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
-
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -61,7 +59,6 @@
import java.util.List;
import javax.inject.Inject;
-import javax.inject.Named;
/** */
@QSScope
@@ -110,25 +107,21 @@
private final AccessibilityDelegateCompat mAccessibilityDelegate;
private RecyclerView mRecyclerView;
private int mNumColumns;
- private final boolean mUseHorizontalTiles;
@Inject
public TileAdapter(
@QSThemedContext Context context,
QSTileHost qsHost,
- UiEventLogger uiEventLogger,
- @Named(QS_LABELS_FLAG) boolean useHorizontalTiles
- ) {
+ UiEventLogger uiEventLogger) {
mContext = context;
mHost = qsHost;
mUiEventLogger = uiEventLogger;
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
mDecoration = new TileItemDecoration(context);
- mMarginDecoration = new MarginTileDecoration(!useHorizontalTiles);
+ mMarginDecoration = new MarginTileDecoration();
mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
mNumColumns = context.getResources().getInteger(NUM_COLUMNS_ID);
mAccessibilityDelegate = new TileAdapterDelegate();
- mUseHorizontalTiles = useHorizontalTiles;
mSizeLookup.setSpanIndexCacheEnabled(true);
}
@@ -287,9 +280,7 @@
}
FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
false);
- View view = mUseHorizontalTiles
- ? new CustomizeTileViewHorizontal(context, new QSIconViewImpl(context))
- : new CustomizeTileView(context, new QSIconViewImpl(context));
+ View view = new CustomizeTileViewHorizontal(context, new QSIconViewImpl(context));
frame.addView(view);
return new Holder(frame);
}
@@ -715,11 +706,6 @@
private static class MarginTileDecoration extends ItemDecoration {
private int mHalfMargin;
- private final boolean mUseOutsideMargins;
-
- private MarginTileDecoration(boolean useOutsideMargins) {
- mUseOutsideMargins = useOutsideMargins;
- }
public void setHalfMargin(int halfMargin) {
mHalfMargin = halfMargin;
@@ -738,9 +724,9 @@
if (view instanceof TextView) {
super.getItemOffsets(outRect, view, parent, state);
} else {
- if (mUseOutsideMargins || (column != 0 && column != lm.getSpanCount() - 1)) {
- // Using outside margins or in a column that's not leftmost or rightmost
- // (half of the margin between columns).
+ if (column != 0 && column != lm.getSpanCount() - 1) {
+ // In a column that's not leftmost or rightmost (half of the margin between
+ // columns).
outRect.left = mHalfMargin;
outRect.right = mHalfMargin;
} else if (column == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 10192bc..a1e1d64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -30,18 +30,11 @@
@Module
public interface QSFlagsModule {
- String QS_LABELS_FLAG = "qs_labels_flag";
+
String RBC_AVAILABLE = "rbc_available";
String PM_LITE_ENABLED = "pm_lite";
String PM_LITE_SETTING = "sysui_pm_lite";
- @Provides
- @SysUISingleton
- @Named(QS_LABELS_FLAG)
- static boolean provideQSFlag(FeatureFlags featureFlags) {
- return featureFlags.isQSLabelsEnabled();
- }
-
/** */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 9b0536c..3437dd5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -14,8 +14,6 @@
package com.android.systemui.qs.tileimpl;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
-
import android.content.Context;
import android.os.Build;
import android.util.Log;
@@ -56,7 +54,6 @@
import com.android.systemui.util.leak.GarbageMonitor;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Provider;
import dagger.Lazy;
@@ -97,12 +94,9 @@
private final Lazy<QSHost> mQsHostLazy;
private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
- private final boolean mSideLabels;
-
@Inject
public QSFactoryImpl(
Lazy<QSHost> qsHostLazy,
- @Named(QS_LABELS_FLAG) boolean useSideLabels,
Provider<CustomTile.Builder> customTileBuilderProvider,
Provider<WifiTile> wifiTileProvider,
Provider<InternetTile> internetTileProvider,
@@ -134,8 +128,6 @@
mQsHostLazy = qsHostLazy;
mCustomTileBuilderProvider = customTileBuilderProvider;
- mSideLabels = useSideLabels;
-
mWifiTileProvider = wifiTileProvider;
mInternetTileProvider = internetTileProvider;
mBluetoothTileProvider = bluetoothTileProvider;
@@ -251,12 +243,6 @@
@Override
public QSTileView createTileView(Context context, QSTile tile, boolean collapsedView) {
QSIconView icon = tile.createTileView(context);
- if (mSideLabels) {
- return new QSTileViewHorizontal(context, icon, collapsedView);
- } else if (collapsedView) {
- return new QSTileBaseView(context, icon, collapsedView);
- } else {
- return new com.android.systemui.qs.tileimpl.QSTileView(context, icon);
- }
+ return new QSTileViewHorizontal(context, icon, collapsedView);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index aa8ce85..ba69dd5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -66,9 +66,9 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSEvent;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SideLabelTileLayout;
import com.android.systemui.qs.logging.QSLogger;
import java.io.FileDescriptor;
@@ -497,7 +497,7 @@
private void updateIsFullQs() {
for (Object listener : mListeners) {
- if (TilePage.class.equals(listener.getClass())) {
+ if (SideLabelTileLayout.class.equals(listener.getClass())) {
mIsFullQs = 1;
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index afbb197..6d23739 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -24,7 +24,6 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -62,7 +61,6 @@
import android.os.UserHandle;
import android.util.Log;
import android.view.InputDevice;
-import android.view.InputMonitor;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -89,7 +87,6 @@
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -358,24 +355,6 @@
}
@Override
- public Bundle monitorGestureInput(String name, int displayId) {
- if (!verifyCaller("monitorGestureInput")) {
- return null;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- final InputMonitor monitor =
- InputManager.getInstance().monitorGestureInput(name, displayId);
- final Bundle result = new Bundle();
- result.putParcelable(KEY_EXTRA_INPUT_MONITOR,
- InputMonitorCompat.obtainReturnValue(monitor));
- return result;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
public void notifyAccessibilityButtonClicked(int displayId) {
if (!verifyCaller("notifyAccessibilityButtonClicked")) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index ec3a857..17b489c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -53,11 +53,6 @@
return mFlagReader.isEnabled(R.bool.flag_notification_twocolumn);
}
- // Does not support runtime changes
- public boolean isQSLabelsEnabled() {
- return mFlagReader.isEnabled(R.bool.flag_qs_labels);
- }
-
public boolean isKeyguardLayoutEnabled() {
return mFlagReader.isEnabled(R.bool.flag_keyguard_layout);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index f57fd21..f4266a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -41,6 +41,7 @@
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
@@ -82,6 +83,9 @@
private Rect mClipRect = new Rect();
private int mCutoutHeight;
private int mGapHeight;
+ private int mIndexOfFirstViewInShelf = -1;
+ private int mIndexOfFirstViewInOverflowingSection = -1;
+
private NotificationShelfController mController;
public NotificationShelf(Context context, AttributeSet attrs) {
@@ -159,30 +163,49 @@
}
/** Update the state of the shelf. */
- public void updateState(AmbientState ambientState) {
+ public void updateState(StackScrollAlgorithm.StackScrollAlgorithmState algorithmState,
+ AmbientState ambientState) {
ExpandableView lastView = ambientState.getLastVisibleBackgroundChild();
ShelfState viewState = (ShelfState) getViewState();
if (mShowNotificationShelf && lastView != null) {
- float maxShelfEnd = ambientState.getInnerHeight() + ambientState.getTopPadding()
- + ambientState.getStackTranslation();
ExpandableViewState lastViewState = lastView.getViewState();
- float viewEnd = lastViewState.yTranslation + lastViewState.height;
viewState.copyFrom(lastViewState);
+
viewState.height = getIntrinsicHeight();
- viewState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height,
- getFullyClosedTranslation());
viewState.zTranslation = ambientState.getBaseZHeight();
viewState.clipTopAmount = 0;
viewState.alpha = 1f - ambientState.getHideAmount();
viewState.belowSpeedBump = mHostLayoutController.getSpeedBumpIndex() == 0;
viewState.hideSensitive = false;
viewState.xTranslation = getTranslationX();
+ viewState.hasItemsInStableShelf = lastViewState.inShelf;
+ viewState.firstViewInShelf = algorithmState.firstViewInShelf;
+ viewState.firstViewInOverflowSection = algorithmState.firstViewInOverflowSection;
if (mNotGoneIndex != -1) {
viewState.notGoneIndex = Math.min(viewState.notGoneIndex, mNotGoneIndex);
}
- viewState.hasItemsInStableShelf = lastViewState.inShelf;
+
viewState.hidden = !mAmbientState.isShadeExpanded()
- || mAmbientState.isQsCustomizerShowing();
+ || mAmbientState.isQsCustomizerShowing()
+ || algorithmState.firstViewInShelf == null;
+
+ final int indexOfFirstViewInShelf = algorithmState.visibleChildren.indexOf(
+ algorithmState.firstViewInShelf);
+
+ if (mAmbientState.isExpansionChanging()
+ && algorithmState.firstViewInShelf != null
+ && indexOfFirstViewInShelf > 0) {
+
+ // Show shelf if section before it is showing.
+ final ExpandableView viewBeforeShelf = algorithmState.visibleChildren.get(
+ indexOfFirstViewInShelf - 1);
+ if (viewBeforeShelf.getViewState().hidden) {
+ viewState.hidden = true;
+ }
+ }
+
+ final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
+ viewState.yTranslation = stackEnd - viewState.height;
} else {
viewState.hidden = true;
viewState.location = ExpandableViewState.LOCATION_GONE;
@@ -199,13 +222,11 @@
if (!mShowNotificationShelf) {
return;
}
-
mShelfIcons.resetViewStates();
float shelfStart = getTranslationY();
float numViewsInShelf = 0.0f;
View lastChild = mAmbientState.getLastVisibleBackgroundChild();
mNotGoneIndex = -1;
- float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2;
// find the first view that doesn't overlap with the shelf
int notGoneIndex = 0;
int colorOfViewBeforeLast = NO_COLOR;
@@ -219,7 +240,7 @@
float currentScrollVelocity = mAmbientState.getCurrentScrollVelocity();
boolean scrollingFast = currentScrollVelocity > mScrollFastThreshold
|| (mAmbientState.isExpansionChanging()
- && Math.abs(mAmbientState.getExpandingVelocity()) > mScrollFastThreshold);
+ && Math.abs(mAmbientState.getExpandingVelocity()) > mScrollFastThreshold);
boolean expandingAnimated = mAmbientState.isExpansionChanging()
&& !mAmbientState.isPanelTracking();
int baseZHeight = mAmbientState.getBaseZHeight();
@@ -233,22 +254,37 @@
if (!child.needsClippingToShelf() || child.getVisibility() == GONE) {
continue;
}
-
float notificationClipEnd;
boolean aboveShelf = ViewState.getFinalTranslationZ(child) > baseZHeight
|| child.isPinned();
boolean isLastChild = child == lastChild;
float rowTranslationY = child.getTranslationY();
+
+ final float inShelfAmount = updateShelfTransformation(i, child, scrollingFast,
+ expandingAnimated, isLastChild);
+
+ final float stackEnd = mAmbientState.getStackY()
+ + mAmbientState.getStackHeight();
+ // TODO(b/172289889) scale mPaddingBetweenElements with expansion amount
if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) {
- notificationClipEnd = shelfStart + getIntrinsicHeight();
+ notificationClipEnd = stackEnd;
+ } else if (mAmbientState.isExpansionChanging()) {
+ if (mIndexOfFirstViewInOverflowingSection != -1
+ && i >= mIndexOfFirstViewInOverflowingSection) {
+ // Clip notifications in (section overflowing into shelf) to shelf start.
+ notificationClipEnd = shelfStart - mPaddingBetweenElements;
+ } else {
+ // Clip notifications before the section overflowing into shelf
+ // to stackEnd because we do not show the shelf if the section right before the
+ // shelf is still hidden.
+ notificationClipEnd = stackEnd;
+ }
} else {
notificationClipEnd = shelfStart - mPaddingBetweenElements;
}
int clipTop = updateNotificationClipHeight(child, notificationClipEnd, notGoneIndex);
clipTopAmount = Math.max(clipTop, clipTopAmount);
- final float inShelfAmount = updateShelfTransformation(child, scrollingFast,
- expandingAnimated, isLastChild);
// If the current row is an ExpandableNotificationRow, update its color, roundedness,
// and icon state.
if (child instanceof ExpandableNotificationRow) {
@@ -314,19 +350,23 @@
distanceToGapTop / mGapHeight);
previousAnv.setBottomRoundness(firstElementRoundness,
false /* don't animate */);
- backgroundTop = (int) distanceToGapBottom;
}
}
previousAnv = anv;
}
}
+
clipTransientViews();
setClipTopAmount(clipTopAmount);
- boolean isHidden = getViewState().hidden || clipTopAmount >= getIntrinsicHeight();
- if (mShowNotificationShelf) {
- setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
- }
+
+ boolean isHidden = getViewState().hidden
+ || clipTopAmount >= getIntrinsicHeight()
+ || !mShowNotificationShelf
+ || numViewsInShelf < 1f;
+
+ // TODO(b/172289889) transition last icon in shelf to notification icon and vice versa.
+ setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
setBackgroundTop(backgroundTop);
setFirstElementRoundness(firstElementRoundness);
mShelfIcons.setSpeedBumpIndex(mHostLayoutController.getSpeedBumpIndex());
@@ -339,11 +379,10 @@
continue;
}
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- updateIconClipAmount(row);
updateContinuousClipping(row);
}
- boolean hideBackground = numViewsInShelf < 1.0f;
- setHideBackground(hideBackground || backgroundForceHidden);
+ boolean hideBackground = isHidden;
+ setHideBackground(hideBackground);
if (mNotGoneIndex == -1) {
mNotGoneIndex = notGoneIndex;
}
@@ -476,10 +515,10 @@
/**
* @return the amount how much this notification is in the shelf
*/
- private float updateShelfTransformation(ExpandableView view, boolean scrollingFast,
+ private float updateShelfTransformation(int i, ExpandableView view, boolean scrollingFast,
boolean expandingAnimated, boolean isLastChild) {
- // Let calculate how much the view is in the shelf
+ // Let's calculate how much the view is in the shelf
float viewStart = view.getTranslationY();
int fullHeight = view.getActualHeight() + mPaddingBetweenElements;
float iconTransformStart = calculateIconTransformationStart(view);
@@ -496,15 +535,21 @@
transformDistance,
view.getMinHeight() - getIntrinsicHeight());
}
+
float viewEnd = viewStart + fullHeight;
float fullTransitionAmount = 0.0f;
float iconTransitionAmount = 0.0f;
float shelfStart = getTranslationY();
-
- if (viewEnd >= shelfStart
+ if (mAmbientState.isExpansionChanging() && !mAmbientState.isOnKeyguard()) {
+ // TODO(b/172289889) handle icon placement for notification that is clipped by the shelf
+ if (mIndexOfFirstViewInShelf != -1 && i >= mIndexOfFirstViewInShelf) {
+ fullTransitionAmount = 1f;
+ iconTransitionAmount = 1f;
+ }
+ } else if (viewEnd >= shelfStart
&& (!mAmbientState.isUnlockHintRunning() || view.isInShelf())
&& (mAmbientState.isShadeExpanded()
- || (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) {
+ || (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) {
if (viewStart < shelfStart) {
float fullAmount = (shelfStart - viewStart) / fullHeight;
@@ -572,7 +617,7 @@
&& !mNoAnimationsInThisFrame;
}
iconState.clampedAppearAmount = clampedAmount;
- setIconTransformationAmount(view, transitionAmount, isLastChild);
+ setIconTransformationAmount(view, transitionAmount);
}
private boolean isTargetClipped(ExpandableView view) {
@@ -585,12 +630,10 @@
+ view.getContentTranslation()
+ view.getRelativeTopPadding(target)
+ target.getHeight();
-
return endOfTarget >= getTranslationY() - mPaddingBetweenElements;
}
- private void setIconTransformationAmount(ExpandableView view, float transitionAmount,
- boolean isLastChild) {
+ private void setIconTransformationAmount(ExpandableView view, float transitionAmount) {
if (!(view instanceof ExpandableNotificationRow)) {
return;
}
@@ -601,7 +644,6 @@
return;
}
iconState.alpha = transitionAmount;
-
boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
iconState.hidden = isAppearing
|| (view instanceof ExpandableNotificationRow
@@ -610,8 +652,8 @@
|| (transitionAmount == 0.0f && !iconState.isAnimating(icon))
|| row.isAboveShelf()
|| row.showingPulsing()
- || (!row.isInShelf() && isLastChild)
|| row.getTranslationZ() > mAmbientState.getBaseZHeight();
+
iconState.iconAppearAmount = iconState.hidden? 0f : transitionAmount;
// Fade in icons at shelf start
@@ -790,8 +832,19 @@
mController = notificationShelfController;
}
+ public void setIndexOfFirstViewInShelf(ExpandableView firstViewInShelf) {
+ mIndexOfFirstViewInShelf = mHostLayoutController.indexOfChild(firstViewInShelf);
+ }
+
+ public void setFirstViewInOverflowingSection(ExpandableView firstViewInOverflowingSection) {
+ mIndexOfFirstViewInOverflowingSection =
+ mHostLayoutController.indexOfChild(firstViewInOverflowingSection);
+ }
+
private class ShelfState extends ExpandableViewState {
private boolean hasItemsInStableShelf;
+ private ExpandableView firstViewInShelf;
+ private ExpandableView firstViewInOverflowSection;
@Override
public void applyToView(View view) {
@@ -800,6 +853,8 @@
}
super.applyToView(view);
+ setIndexOfFirstViewInShelf(firstViewInShelf);
+ setFirstViewInOverflowingSection(firstViewInOverflowSection);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
@@ -812,6 +867,8 @@
}
super.animateTo(child, properties);
+ setIndexOfFirstViewInShelf(firstViewInShelf);
+ setFirstViewInOverflowingSection(firstViewInOverflowSection);
updateAppearance();
setHasItemsInStableShelf(hasItemsInStableShelf);
mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
index 1e935c1..4f70fdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
@@ -22,6 +22,7 @@
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.phone.StatusBarNotificationPresenter;
@@ -103,9 +104,10 @@
return mView.getHeight();
}
- public void updateState(AmbientState ambientState) {
+ public void updateState(StackScrollAlgorithm.StackScrollAlgorithmState algorithmState,
+ AmbientState ambientState) {
mAmbientState = ambientState;
- mView.updateState(ambientState);
+ mView.updateState(algorithmState, ambientState);
}
public int getIntrinsicHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index c811fdd..a537299 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -25,12 +25,14 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.DimenRes;
+import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import com.android.internal.annotations.GuardedBy;
@@ -66,6 +68,8 @@
private Executor mChangeRunnableExecutor;
private Executor mExecutor;
private Looper mExecutorLooper;
+ @Nullable
+ private Rect mDrawableBounds;
public ScrimView(Context context) {
this(context, null);
@@ -125,7 +129,9 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (changed) {
+ if (mDrawableBounds != null) {
+ mDrawable.setBounds(mDrawableBounds);
+ } else if (changed) {
mDrawable.setBounds(left, top, right, bottom);
invalidate();
}
@@ -288,4 +294,15 @@
((ScrimDrawable) mDrawable).setRoundedCorners(radius);
}
}
+
+ /**
+ * Set bounds for the view, all coordinates are absolute
+ */
+ public void setDrawableBounds(float left, float top, float right, float bottom) {
+ if (mDrawableBounds == null) {
+ mDrawableBounds = new Rect();
+ }
+ mDrawableBounds.set((int) left, (int) top, (int) right, (int) bottom);
+ mDrawable.setBounds(mDrawableBounds);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index fd060e6..718a85a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -58,6 +58,7 @@
title = "Wired Charging Animation"
flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+ setTrustedOverlay()
}
@VisibleForTesting
@@ -103,7 +104,10 @@
}
fun startRipple() {
- if (rippleView.rippleInProgress) {
+ if (rippleView.rippleInProgress || rippleView.parent != null) {
+ // Skip if ripple is still playing, or not playing but already added the parent
+ // (which might happen just before the animation starts or right after
+ // the animation ends.)
return
}
val mWM = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
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 8fae720..500838f 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
@@ -71,7 +71,6 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
-import com.android.internal.widget.MessagingLayout;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -658,10 +657,6 @@
boolean beforeS = mEntry.targetSdk < Build.VERSION_CODES.S;
int smallHeight;
- View expandedView = layout.getExpandedChild();
- boolean isMediaLayout = expandedView != null
- && expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
- boolean isMessagingLayout = contractedView instanceof MessagingLayout;
boolean isCallLayout = contractedView instanceof CallLayout;
if (customView && beforeS && !mIsSummaryWithChildren) {
@@ -672,12 +667,6 @@
} else {
smallHeight = mMaxSmallHeightBeforeS;
}
- } else if (isMessagingLayout) {
- // TODO(b/173204301): MessagingStyle notifications currently look broken when we enforce
- // the standard notification height, so we have to afford them more vertical space to
- // make sure we don't crop them terribly. We actually need to revisit this and give
- // them a headerless design, then remove this hack.
- smallHeight = mMaxSmallHeightLarge;
} else if (isCallLayout) {
smallHeight = mMaxExpandedHeight;
} else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 383bb7e..08981f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -23,12 +23,9 @@
import com.android.internal.widget.ConversationLayout
import com.android.internal.widget.MessagingLinearLayout
import com.android.systemui.R
-import com.android.systemui.statusbar.TransformableView
-import com.android.systemui.statusbar.ViewTransformationHelper
import com.android.systemui.statusbar.notification.NotificationUtils
-import com.android.systemui.statusbar.notification.TransformState
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.notification.row.HybridNotificationView
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationMessagingTemplateViewWrapper.setCustomImageMessageTransform
/**
* Wraps a notification containing a conversation template
@@ -93,33 +90,7 @@
appName,
conversationTitleView)
- // Let's ignore the image message container since that is transforming as part of the
- // messages already
- mTransformationHelper.setCustomTransformation(
- object : ViewTransformationHelper.CustomTransformation() {
- override fun transformTo(
- ownState: TransformState,
- otherView: TransformableView,
- transformationAmount: Float
- ): Boolean {
- if (otherView is HybridNotificationView) {
- return false
- }
- // we're hidden by default by the transformState
- ownState.ensureVisible()
- // Let's do nothing otherwise, this is already handled by the messages
- return true
- }
-
- override fun transformFrom(
- ownState: TransformState,
- otherView: TransformableView,
- transformationAmount: Float
- ): Boolean =
- transformTo(ownState, otherView, transformationAmount)
- },
- imageMessageContainer.id
- )
+ setCustomImageMessageTransform(mTransformationHelper, imageMessageContainer)
addViewsTransformingToSimilar(
conversationIconView,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
index c9a2742..c587ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapper.java
@@ -18,12 +18,17 @@
import android.content.Context;
import android.view.View;
+import android.view.ViewGroup;
import com.android.internal.widget.MessagingLayout;
import com.android.internal.widget.MessagingLinearLayout;
import com.android.systemui.R;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.TransformState;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.HybridNotificationView;
/**
* Wraps a notification containing a messaging template
@@ -31,12 +36,17 @@
public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
private final int mMinHeightWithActions;
+ private final View mTitle;
+ private final View mTitleInHeader;
private MessagingLayout mMessagingLayout;
private MessagingLinearLayout mMessagingLinearLayout;
+ private ViewGroup mImageMessageContainer;
protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
+ mTitle = mView.findViewById(com.android.internal.R.id.title);
+ mTitleInHeader = mView.findViewById(com.android.internal.R.id.header_text_secondary);
mMessagingLayout = (MessagingLayout) view;
mMinHeightWithActions = NotificationUtils.getFontScaledHeight(ctx,
R.dimen.notification_messaging_actions_min_height);
@@ -44,6 +54,7 @@
private void resolveViews() {
mMessagingLinearLayout = mMessagingLayout.getMessagingLinearLayout();
+ mImageMessageContainer = mMessagingLayout.getImageMessageContainer();
}
@Override
@@ -59,8 +70,48 @@
// This also clears the existing types
super.updateTransformedTypes();
if (mMessagingLinearLayout != null) {
- mTransformationHelper.addTransformedView(mMessagingLinearLayout.getId(),
- mMessagingLinearLayout);
+ mTransformationHelper.addTransformedView(mMessagingLinearLayout);
+ }
+ // The title is not as important for messaging, and stays in the header when expanded,
+ // but this ensures it animates cleanly between the two positions
+ if (mTitle == null && mTitleInHeader != null) {
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
+ mTitleInHeader);
+ }
+ setCustomImageMessageTransform(mTransformationHelper, mImageMessageContainer);
+ }
+
+ static void setCustomImageMessageTransform(
+ ViewTransformationHelper transformationHelper, ViewGroup imageMessageContainer) {
+ if (imageMessageContainer != null) {
+ // Let's ignore the image message container since that is transforming as part of the
+ // messages already. This is also required to prevent a clipping artifact caused by the
+ // alpha layering triggering hardware rendering mode that in turn results in more
+ // aggressive clipping than we want.
+ transformationHelper.setCustomTransformation(
+ new ViewTransformationHelper.CustomTransformation() {
+ @Override
+ public boolean transformTo(
+ TransformState ownState,
+ TransformableView otherView,
+ float transformationAmount) {
+ if (otherView instanceof HybridNotificationView) {
+ return false;
+ }
+ // we're hidden by default by the transformState
+ ownState.ensureVisible();
+ // Let's do nothing otherwise, this is already handled by the messages
+ return true;
+ }
+
+ @Override
+ public boolean transformFrom(
+ TransformState ownState,
+ TransformableView otherView,
+ float transformationAmount) {
+ return transformTo(ownState, otherView, transformationAmount);
+ }
+ }, imageMessageContainer.getId());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index e0b5812..48f34b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -56,6 +56,7 @@
private ProgressBar mProgressBar;
private TextView mTitle;
private TextView mText;
+ protected View mSmartReplyContainer;
protected View mActionsContainer;
private int mContentHeight;
@@ -160,6 +161,7 @@
// It's still a viewstub
mProgressBar = null;
}
+ mSmartReplyContainer = mView.findViewById(com.android.internal.R.id.smart_reply_container);
mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
mActions = mView.findViewById(com.android.internal.R.id.actions);
mRemoteInputHistory = mView.findViewById(
@@ -275,6 +277,7 @@
mProgressBar);
}
addViewsTransformingToSimilar(mLeftIcon);
+ addTransformedViews(mSmartReplyContainer);
}
@Override
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 8446b4e6..caf4720 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
@@ -60,7 +60,7 @@
private NotificationShelf mShelf;
private int mZDistanceBetweenElements;
private int mBaseZHeight;
- private int mMaxLayoutHeight;
+ private int mContentHeight;
private ExpandableView mLastVisibleBackgroundChild;
private float mCurrentScrollVelocity;
private int mStatusBarState;
@@ -84,6 +84,75 @@
private boolean mIsShadeOpening;
private float mSectionPadding;
+ /** Distance of top of notifications panel from top of screen. */
+ private float mStackY = 0;
+
+ /** Height of notifications panel. */
+ private float mStackHeight = 0;
+
+ /** Fraction of shade expansion. */
+ private float mExpansionFraction;
+
+ /** Height of the notifications panel without top padding when expansion completes. */
+ private float mStackEndHeight;
+
+ /**
+ * @return Height of the notifications panel without top padding when expansion completes.
+ */
+ public float getStackEndHeight() {
+ return mStackEndHeight;
+ }
+
+ /**
+ * @param stackEndHeight Height of the notifications panel without top padding
+ * when expansion completes.
+ */
+ public void setStackEndHeight(float stackEndHeight) {
+ mStackEndHeight = stackEndHeight;
+ }
+
+ /**
+ * @param stackY Distance of top of notifications panel from top of screen.
+ */
+ public void setStackY(float stackY) {
+ mStackY = stackY;
+ }
+
+ /**
+ * @return Distance of top of notifications panel from top of screen.
+ */
+ public float getStackY() {
+ return mStackY;
+ }
+
+ /**
+ * @param expansionFraction Fraction of shade expansion.
+ */
+ public void setExpansionFraction(float expansionFraction) {
+ mExpansionFraction = expansionFraction;
+ }
+
+ /**
+ * @return Fraction of shade expansion.
+ */
+ public float getExpansionFraction() {
+ return mExpansionFraction;
+ }
+
+ /**
+ * @param stackHeight Height of notifications panel.
+ */
+ public void setStackHeight(float stackHeight) {
+ mStackHeight = stackHeight;
+ }
+
+ /**
+ * @return Height of notifications panel.
+ */
+ public float getStackHeight() {
+ return mStackHeight;
+ }
+
/** Tracks the state from AlertingNotificationManager#hasNotifications() */
private boolean mHasAlertEntries;
@@ -263,8 +332,8 @@
if (mDozeAmount == 1.0f && !isPulseExpanding()) {
return mShelf.getHeight();
}
- int height = Math.max(mLayoutMinHeight,
- Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding);
+ int height = (int) Math.max(mLayoutMinHeight,
+ Math.min(mLayoutHeight, mContentHeight) - mTopPadding);
if (ignorePulseHeight) {
return height;
}
@@ -313,8 +382,12 @@
return mShelf;
}
- public void setLayoutMaxHeight(int maxLayoutHeight) {
- mMaxLayoutHeight = maxLayoutHeight;
+ public void setContentHeight(int contentHeight) {
+ mContentHeight = contentHeight;
+ }
+
+ public float getContentHeight() {
+ return mContentHeight;
}
/**
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 fb72ac3..733a9f6 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
@@ -658,6 +658,14 @@
y = getHeight() - getEmptyBottomMargin();
mDebugPaint.setColor(Color.GREEN);
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+
+ y = (int) (mAmbientState.getStackY());
+ mDebugPaint.setColor(Color.CYAN);
+ canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+
+ y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
+ mDebugPaint.setColor(Color.BLUE);
+ canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
}
}
@@ -1123,18 +1131,37 @@
mTopPaddingNeedsAnimation = true;
mNeedsAnimation = true;
}
+ updateStackPosition();
requestChildrenUpdate();
notifyHeightChangeListener(null, animate);
}
}
/**
+ * Apply expansion fraction to the y position and height of the notifications panel.
+ */
+ private void updateStackPosition() {
+ // Consider interpolating from an mExpansionStartY for use on lockscreen and AOD
+ mAmbientState.setStackY(
+ MathUtils.lerp(0, mTopPadding, mAmbientState.getExpansionFraction()));
+ final float shadeBottom = getHeight() - getEmptyBottomMargin();
+ mAmbientState.setStackEndHeight(shadeBottom - mTopPadding);
+ mAmbientState.setStackHeight(
+ MathUtils.lerp(0, shadeBottom - mTopPadding, mAmbientState.getExpansionFraction()));
+ }
+
+ /**
* Update the height of the panel.
*
* @param height the expanded height of the panel
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setExpandedHeight(float height) {
+ final float shadeBottom = getHeight() - getEmptyBottomMargin();
+ final float expansionFraction = MathUtils.constrain(height / shadeBottom, 0f, 1f);
+ mAmbientState.setExpansionFraction(expansionFraction);
+ updateStackPosition();
+
mExpandedHeight = height;
setIsExpanded(height > 0);
int minExpansionHeight = getMinExpansionHeight();
@@ -2067,7 +2094,8 @@
mContentHeight = height + Math.max(mIntrinsicPadding, mTopPadding) + mBottomMargin;
updateScrollability();
clampScrollPosition();
- mAmbientState.setLayoutMaxHeight(mContentHeight);
+ updateStackPosition();
+ mAmbientState.setContentHeight(mContentHeight);
}
/**
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 7776e69..4fc49ed 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
@@ -788,6 +788,10 @@
return mView.getTranslationX();
}
+ public int indexOfChild(View view) {
+ return mView.indexOfChild(view);
+ }
+
public void setOnHeightChangedListener(
ExpandableView.OnHeightChangedListener listener) {
mView.setOnHeightChangedListener(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index bbdbe80..3e1a781 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -20,21 +20,22 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
-import android.util.Log;
import android.util.MathUtils;
import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.R;
-import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.notification.dagger.SilentHeader;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.FooterView;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* The Algorithm of the {@link com.android.systemui.statusbar.notification.stack
@@ -92,20 +93,16 @@
// First we reset the view states to their default values.
resetChildViewStates();
-
initAlgorithmState(mHostView, algorithmState, ambientState);
-
updatePositionsForState(algorithmState, ambientState);
-
updateZValuesForState(algorithmState, ambientState);
-
updateHeadsUpStates(algorithmState, ambientState);
updatePulsingStates(algorithmState, ambientState);
updateDimmedActivatedHideSensitive(ambientState, algorithmState);
updateClipping(algorithmState, ambientState);
updateSpeedBumpState(algorithmState, speedBumpIndex);
- updateShelfState(ambientState);
+ updateShelfState(algorithmState, ambientState);
getNotificationChildrenStates(algorithmState, ambientState);
}
@@ -144,10 +141,13 @@
}
- private void updateShelfState(AmbientState ambientState) {
+ private void updateShelfState(
+ StackScrollAlgorithmState algorithmState,
+ AmbientState ambientState) {
+
NotificationShelf shelf = ambientState.getShelf();
if (shelf != null) {
- shelf.updateState(ambientState);
+ shelf.updateState(algorithmState, ambientState);
}
}
@@ -172,7 +172,8 @@
&& ((ExpandableNotificationRow) child).isPinned();
if (mClipNotificationScrollToTop
&& (!state.inShelf || (isHeadsUp && !firstHeadsUp))
- && newYTranslation < clipStart) {
+ && newYTranslation < clipStart
+ && !ambientState.isShadeOpening()) {
// The previous view is overlapping on top, clip!
float overlapAmount = clipStart - newYTranslation;
state.clipTopAmount = (int) overlapAmount;
@@ -217,7 +218,6 @@
private void initAlgorithmState(ViewGroup hostView, StackScrollAlgorithmState state,
AmbientState ambientState) {
float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
-
int scrollY = ambientState.getScrollY();
// Due to the overScroller, the stackscroller can have negative scroll state. This is
@@ -230,7 +230,6 @@
state.visibleChildren.clear();
state.visibleChildren.ensureCapacity(childCount);
int notGoneIndex = 0;
- ExpandableView lastView = null;
for (int i = 0; i < childCount; i++) {
ExpandableView v = (ExpandableView) hostView.getChildAt(i);
if (v.getVisibility() != View.GONE) {
@@ -255,12 +254,101 @@
}
}
}
- ExpandableNotificationRow expandingNotification = ambientState.getExpandingNotification();
- state.indexOfExpandingNotification = expandingNotification != null
- ? expandingNotification.isChildInGroup()
- ? state.visibleChildren.indexOf(expandingNotification.getNotificationParent())
- : state.visibleChildren.indexOf(expandingNotification)
- : -1;
+
+ state.firstViewInShelf = null;
+ // Save y, sectionStart, sectionEnd from when shade is fully expanded.
+ // Consider updating these states in updateContentView instead so that we don't have to
+ // recalculate in every frame.
+ float currentY = -scrollY;
+ int sectionStartIndex = 0;
+ int sectionEndIndex = 0;
+ for (int i = 0; i < state.visibleChildren.size(); i++) {
+ final ExpandableView view = state.visibleChildren.get(i);
+ // Add space between sections.
+ final boolean applyGapHeight = childNeedsGapHeight(
+ ambientState.getSectionProvider(), i,
+ view, getPreviousView(i, state));
+ if (applyGapHeight) {
+ currentY += mGapHeight;
+ }
+
+ // Save index of first view in the shelf
+ final float shelfStart = ambientState.getStackEndHeight()
+ - ambientState.getShelf().getIntrinsicHeight();
+ if (currentY >= shelfStart
+ && !(view instanceof FooterView)
+ && state.firstViewInShelf == null) {
+ state.firstViewInShelf = view;
+ }
+
+ // Record y position when fully expanded
+ ExpansionData expansionData = new ExpansionData();
+ expansionData.fullyExpandedY = currentY;
+ state.expansionData.put(view, expansionData);
+
+ if (ambientState.getSectionProvider()
+ .beginsSection(view, getPreviousView(i, state))) {
+
+ // Save section start/end for views in the section before this new section
+ ExpandableView sectionStartView = state.visibleChildren.get(sectionStartIndex);
+ final float sectionStart =
+ state.expansionData.get(sectionStartView).fullyExpandedY;
+
+ ExpandableView sectionEndView = state.visibleChildren.get(sectionEndIndex);
+ float sectionEnd = state.expansionData.get(sectionEndView).fullyExpandedY
+ + sectionEndView.getIntrinsicHeight();
+
+ // If we show the shelf, trim section end to shelf start
+ // This means section end > start for views in the shelf
+ if (state.firstViewInShelf != null && sectionEnd > shelfStart) {
+ sectionEnd = shelfStart;
+ }
+
+ // Update section bounds of every view in the previous section
+ // Consider using shared SectionInfo for views in same section to avoid looping back
+ for (int j = sectionStartIndex; j < i; j++) {
+ ExpandableView sectionView = state.visibleChildren.get(j);
+ ExpansionData viewExpansionData =
+ state.expansionData.get(sectionView);
+ viewExpansionData.sectionStart = sectionStart;
+ viewExpansionData.sectionEnd = sectionEnd;
+ state.expansionData.put(sectionView, viewExpansionData);
+ }
+ sectionStartIndex = i;
+
+ if (view instanceof FooterView) {
+ // Also record section bounds for FooterView (same as its own)
+ // because it is the last view and we won't get to this point again
+ // after the loop ends
+ ExpansionData footerExpansionData = state.expansionData.get(view);
+ footerExpansionData.sectionStart = expansionData.fullyExpandedY;
+ footerExpansionData.sectionEnd = expansionData.fullyExpandedY
+ + view.getIntrinsicHeight();
+ state.expansionData.put(view, footerExpansionData);
+ }
+ }
+ sectionEndIndex = i;
+ currentY = currentY
+ + getMaxAllowedChildHeight(view)
+ + mPaddingBetweenElements;
+ }
+
+ // Which view starts the section of the view right before the shelf?
+ // Save it for later when we clip views in that section to shelf start.
+ state.firstViewInOverflowSection = null;
+ if (state.firstViewInShelf != null) {
+ ExpandableView nextView = null;
+ final int startIndex = state.visibleChildren.indexOf(state.firstViewInShelf);
+ for (int i = startIndex - 1; i >= 0; i--) {
+ ExpandableView view = state.visibleChildren.get(i);
+ if (nextView != null && ambientState.getSectionProvider()
+ .beginsSection(nextView, view)) {
+ break;
+ }
+ nextView = view;
+ }
+ state.firstViewInOverflowSection = nextView;
+ }
}
private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex,
@@ -272,6 +360,10 @@
return notGoneIndex;
}
+ private ExpandableView getPreviousView(int i, StackScrollAlgorithmState algorithmState) {
+ return i > 0 ? algorithmState.visibleChildren.get(i - 1) : null;
+ }
+
/**
* Determine the positions for the views. This is the main part of the algorithm.
*
@@ -288,6 +380,15 @@
}
}
+ private void setLocation(ExpandableViewState expandableViewState, float currentYPosition,
+ int i) {
+ expandableViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
+ if (currentYPosition <= 0) {
+ expandableViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
+ }
+ }
+
+ // TODO(b/172289889) polish shade open from HUN
/**
* Populates the {@link ExpandableViewState} for a single child.
*
@@ -306,53 +407,84 @@
StackScrollAlgorithmState algorithmState,
AmbientState ambientState,
float currentYPosition) {
- ExpandableView child = algorithmState.visibleChildren.get(i);
- ExpandableView previousChild = i > 0 ? algorithmState.visibleChildren.get(i - 1) : null;
+
+ ExpandableView view = algorithmState.visibleChildren.get(i);
+ ExpandableViewState viewState = view.getViewState();
+ viewState.location = ExpandableViewState.LOCATION_UNKNOWN;
+ viewState.alpha = 1f - ambientState.getHideAmount();
+
+ if (view.mustStayOnScreen() && viewState.yTranslation >= 0) {
+ // Even if we're not scrolled away we're in view and we're also not in the
+ // shelf. We can relax the constraints and let us scroll off the top!
+ float end = viewState.yTranslation + viewState.height + ambientState.getStackY();
+ viewState.headsUpIsVisible = end < ambientState.getMaxHeadsUpTranslation();
+ }
+
+ // TODO(b/172289889) move sectionFraction and showSection to initAlgorithmState
+ // Get fraction of section showing, and later apply it to view height and gaps between views
+ float sectionFraction = 1f;
+ boolean showSection = true;
+
+ if (!ambientState.isOnKeyguard()
+ && !ambientState.isPulseExpanding()
+ && ambientState.isExpansionChanging()) {
+
+ final ExpansionData expansionData = algorithmState.expansionData.get(view);
+ final float sectionHeight = expansionData.sectionEnd - expansionData.sectionStart;
+ sectionFraction = MathUtils.constrain(
+ (ambientState.getStackHeight() - expansionData.sectionStart) / sectionHeight,
+ 0f, 1f);
+ showSection = expansionData.sectionStart < ambientState.getStackHeight();
+ }
+
+ // Add gap between sections.
final boolean applyGapHeight =
childNeedsGapHeight(
ambientState.getSectionProvider(), i,
- child, previousChild);
- ExpandableViewState childViewState = child.getViewState();
- childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
-
+ view, getPreviousView(i, algorithmState));
if (applyGapHeight) {
- currentYPosition += mGapHeight;
- }
- int childHeight = getMaxAllowedChildHeight(child);
- childViewState.yTranslation = currentYPosition;
- childViewState.alpha = 1f - ambientState.getHideAmount();
-
- boolean isFooterView = child instanceof FooterView;
- boolean isEmptyShadeView = child instanceof EmptyShadeView;
-
- childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
- float inset = ambientState.getTopPadding() + ambientState.getStackTranslation()
- + ambientState.getSectionPadding();
- if (child.mustStayOnScreen() && childViewState.yTranslation >= 0) {
- // Even if we're not scrolled away we're in view and we're also not in the
- // shelf. We can relax the constraints and let us scroll off the top!
- float end = childViewState.yTranslation + childViewState.height + inset;
- childViewState.headsUpIsVisible = end < ambientState.getMaxHeadsUpTranslation();
- }
- if (isFooterView) {
- childViewState.yTranslation = Math.min(childViewState.yTranslation,
- ambientState.getInnerHeight() - childHeight);
- } else if (isEmptyShadeView) {
- childViewState.yTranslation = ambientState.getInnerHeight() - childHeight
- + ambientState.getStackTranslation() * 0.25f;
- } else if (child != ambientState.getTrackedHeadsUpRow()) {
- clampPositionToShelf(child, childViewState, ambientState);
+ currentYPosition += sectionFraction * mGapHeight;
}
- currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
- if (currentYPosition <= 0) {
- childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
- }
- if (childViewState.location == ExpandableViewState.LOCATION_UNKNOWN) {
- Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
+ viewState.yTranslation = currentYPosition;
+
+ if (view instanceof SectionHeaderView) {
+ // Add padding before sections for overscroll effect.
+ viewState.yTranslation += ambientState.getSectionPadding();
}
- childViewState.yTranslation += inset;
+ if (view != ambientState.getTrackedHeadsUpRow()) {
+ if (ambientState.isExpansionChanging()) {
+ viewState.hidden = !showSection;
+ viewState.inShelf = algorithmState.firstViewInShelf != null
+ && i >= algorithmState.visibleChildren.indexOf(
+ algorithmState.firstViewInShelf)
+ && !(view instanceof FooterView);
+ } else {
+ // When pulsing (incoming notification on AOD), innerHeight is 0; clamp all
+ // to shelf start, thereby hiding all notifications (except the first one, which we
+ // later unhide in updatePulsingState)
+ final int shelfStart = ambientState.getInnerHeight()
+ - ambientState.getShelf().getIntrinsicHeight();
+ if (!(view instanceof FooterView)) {
+ viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart);
+ }
+ if (viewState.yTranslation >= shelfStart) {
+ viewState.hidden = !view.isExpandAnimationRunning()
+ && !view.hasExpandingChild()
+ && !(view instanceof FooterView);
+ viewState.inShelf = true;
+ // Notifications in the shelf cannot be visible HUNs.
+ viewState.headsUpIsVisible = false;
+ }
+ }
+ viewState.height = (int) MathUtils.lerp(
+ 0, getMaxAllowedChildHeight(view), sectionFraction);
+ }
+
+ currentYPosition += viewState.height + sectionFraction * mPaddingBetweenElements;
+ setLocation(view.getViewState(), currentYPosition, i);
+ viewState.yTranslation += ambientState.getStackY();
return currentYPosition;
}
@@ -393,10 +525,10 @@
int visibleIndex,
View child,
View previousChild) {
-
- boolean needsGapHeight = sectionProvider.beginsSection(child, previousChild)
- && visibleIndex > 0;
- return needsGapHeight;
+ return sectionProvider.beginsSection(child, previousChild)
+ && visibleIndex > 0
+ && !(previousChild instanceof SilentHeader)
+ && !(child instanceof FooterView);
}
private void updatePulsingStates(StackScrollAlgorithmState algorithmState,
@@ -514,42 +646,6 @@
childState.yTranslation = newTranslation;
}
- /**
- * Clamp the height of the child down such that its end is at most on the beginning of
- * the shelf.
- *
- * @param childViewState the view state of the child
- * @param ambientState the ambient state
- */
- private void clampPositionToShelf(ExpandableView child,
- ExpandableViewState childViewState,
- AmbientState ambientState) {
- if (ambientState.getShelf() == null) {
- return;
- }
-
- ExpandableNotificationRow trackedHeadsUpRow = ambientState.getTrackedHeadsUpRow();
- boolean isBeforeTrackedHeadsUp = trackedHeadsUpRow != null
- && mHostView.indexOfChild(child) < mHostView.indexOfChild(trackedHeadsUpRow);
-
- int shelfStart = ambientState.getInnerHeight()
- - ambientState.getShelf().getIntrinsicHeight();
- if (ambientState.isAppearing() && !child.isAboveShelf() && !isBeforeTrackedHeadsUp) {
- // Don't show none heads-up notifications while in appearing phase.
- childViewState.yTranslation = Math.max(childViewState.yTranslation, shelfStart);
- }
- childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
- if (child instanceof SectionHeaderView) {
- // Add padding before sections for overscroll effect.
- childViewState.yTranslation += ambientState.getSectionPadding();
- }
- if (childViewState.yTranslation >= shelfStart) {
- childViewState.hidden = !child.isExpandAnimationRunning() && !child.hasExpandingChild();
- childViewState.inShelf = true;
- childViewState.headsUpIsVisible = false;
- }
- }
-
protected int getMaxAllowedChildHeight(View child) {
if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
@@ -641,6 +737,35 @@
this.mIsExpanded = isExpanded;
}
+ /**
+ * Data used to layout views while shade expansion changes.
+ */
+ public class ExpansionData {
+
+ /**
+ * Y position of top of first view in section.
+ */
+ public float sectionStart;
+
+ /**
+ * Y position of bottom of last view in section.
+ */
+ public float sectionEnd;
+
+ /**
+ * Y position of view when shade is fully expanded.
+ * Does not include distance between top notifications panel and top of screen.
+ */
+ public float fullyExpandedY;
+
+ /**
+ * Whether this notification is in the same section as the notification right before the
+ * shelf. Used to determine which notification should be clipped to shelf start while
+ * shade expansion changes.
+ */
+ public boolean inOverflowingSection;
+ }
+
public class StackScrollAlgorithmState {
/**
@@ -649,15 +774,26 @@
public int scrollY;
/**
+ * First view in shelf.
+ */
+ public ExpandableView firstViewInShelf;
+
+ /**
+ * First view in section overflowing into shelf while shade expansion changes.
+ */
+ public ExpandableView firstViewInOverflowSection;
+
+ /**
+ * Map of view to ExpansionData used for layout during shade expansion.
+ * Use view instead of index as key, because visibleChildren indices do not match the ones
+ * used in the shelf.
+ */
+ public Map<ExpandableView, ExpansionData> expansionData = new HashMap<>();
+
+ /**
* The children from the host view which are not gone.
*/
- public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
-
- private int indexOfExpandingNotification;
-
- public int getIndexOfExpandingNotification() {
- return indexOfExpandingNotification;
- }
+ public final ArrayList<ExpandableView> visibleChildren = new ArrayList<>();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 707135c3..30d9841 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -16,11 +16,13 @@
package com.android.systemui.statusbar.phone
+import android.annotation.IntDef
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.biometrics.BiometricSourceType
import android.provider.Settings
import com.android.systemui.Dumpable
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -37,9 +39,18 @@
private val mKeyguardStateController: KeyguardStateController
private val statusBarStateController: StatusBarStateController
+ @BypassOverride private val bypassOverride: Int
private var hasFaceFeature: Boolean
private var pendingUnlock: PendingUnlock? = null
+ @IntDef(
+ FACE_UNLOCK_BYPASS_NO_OVERRIDE,
+ FACE_UNLOCK_BYPASS_ALWAYS,
+ FACE_UNLOCK_BYPASS_NEVER
+ )
+ @Retention(AnnotationRetention.SOURCE)
+ private annotation class BypassOverride
+
/**
* Pending unlock info:
*
@@ -60,7 +71,14 @@
* If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
*/
var bypassEnabled: Boolean = false
- get() = field && mKeyguardStateController.isFaceAuthEnabled
+ get() {
+ val enabled = when (bypassOverride) {
+ FACE_UNLOCK_BYPASS_ALWAYS -> true
+ FACE_UNLOCK_BYPASS_NEVER -> false
+ else -> field
+ }
+ return enabled && mKeyguardStateController.isFaceAuthEnabled
+ }
private set
var bouncerShowing: Boolean = false
@@ -86,6 +104,8 @@
this.mKeyguardStateController = keyguardStateController
this.statusBarStateController = statusBarStateController
+ bypassOverride = context.resources.getInteger(R.integer.config_face_unlock_bypass_override)
+
hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)
if (!hasFaceFeature) {
return
@@ -198,5 +218,9 @@
companion object {
const val BYPASS_PANEL_FADE_DURATION = 67
+
+ private const val FACE_UNLOCK_BYPASS_NO_OVERRIDE = 0
+ private const val FACE_UNLOCK_BYPASS_ALWAYS = 1
+ private const val FACE_UNLOCK_BYPASS_NEVER = 2
}
}
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 6a35293..c4d8840 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -1997,12 +1997,35 @@
float qsExpansionFraction = getQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
- mScrimController.setQsPosition(qsExpansionFraction,
- calculateQsBottomPosition(qsExpansionFraction));
+ int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
+ mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
+ setNotificationBounds(qsExpansionFraction, qsPanelBottomY);
mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
mDepthController.setQsPanelExpansion(qsExpansionFraction);
}
+ private void setNotificationBounds(float qsExpansionFraction, int qsPanelBottomY) {
+ float top = 0;
+ float bottom = 0;
+ float left = 0;
+ float right = 0;
+ if (qsPanelBottomY > 0) {
+ // notification shade is expanding/expanded
+ if (!mShouldUseSplitNotificationShade) {
+ top = qsPanelBottomY;
+ bottom = getView().getBottom();
+ left = getView().getLeft();
+ right = getView().getRight();
+ } else {
+ top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding);
+ bottom = mNotificationStackScrollLayoutController.getHeight();
+ left = mNotificationStackScrollLayoutController.getLeft();
+ right = mNotificationStackScrollLayoutController.getRight();
+ }
+ }
+ mScrimController.setNotificationsBounds(left, top, right, bottom);
+ }
+
private int calculateQsBottomPosition(float qsExpansionFraction) {
int qsBottomY = (int) getHeaderTranslation() + mQs.getQsMinExpansionHeight();
if (qsExpansionFraction != 0.0) {
@@ -2030,7 +2053,7 @@
private float calculateNotificationsTopPadding() {
if (mShouldUseSplitNotificationShade && !mKeyguardShowing) {
- return mSplitShadeNotificationsTopPadding;
+ return mSplitShadeNotificationsTopPadding + mQsNotificationTopPadding;
}
if (mKeyguardShowing && (mQsExpandImmediate
|| mIsExpanding && mQsExpandedWhenExpandingStarted)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 58488ef..5e9c758 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -487,6 +487,13 @@
}
/**
+ * Set bounds for notifications background, all coordinates are absolute
+ */
+ public void setNotificationsBounds(float left, float top, float right, float bottom) {
+ mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
+ }
+
+ /**
* Current state of the QuickSettings when pulling it from the top.
*
* @param expansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
@@ -496,7 +503,6 @@
if (isNaN(expansionFraction)) {
return;
}
- shiftNotificationsScrim(qsPanelBottomY);
updateNotificationsScrimAlpha(expansionFraction, qsPanelBottomY);
if (mQsExpansion != expansionFraction) {
mQsExpansion = expansionFraction;
@@ -511,14 +517,6 @@
}
}
- private void shiftNotificationsScrim(int qsPanelBottomY) {
- if (qsPanelBottomY > 0) {
- mNotificationsScrim.setTranslationY(qsPanelBottomY);
- } else {
- mNotificationsScrim.setTranslationY(0);
- }
- }
-
private void updateNotificationsScrimAlpha(float qsExpansion, int qsPanelBottomY) {
float newAlpha = 0;
if (qsPanelBottomY > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index 662e25c..4284148 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -233,7 +233,7 @@
return null;
}
final AppEntry appEntry = appState.getEntry(packageName, userId);
- if (appEntry.info == null
+ if (appEntry == null || appEntry.info == null
|| !ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(appEntry)) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 55b80dd..db77366 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -633,7 +633,7 @@
} else {
mNotificationGroupManager.onEntryRemoved(entry);
}
- });
+ }, mSysuiMainExecutor);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 9017dd2..a870915 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -31,6 +32,7 @@
import android.testing.AndroidTestingRunner;
import android.util.AttributeSet;
import android.view.View;
+import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.android.internal.colorextraction.ColorExtractor;
@@ -48,6 +50,7 @@
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
@@ -98,9 +101,14 @@
@Mock
private AnimatableClockView mLargeClockView;
@Mock
+ private FrameLayout mLargeClockFrame;
+ @Mock
BatteryController mBatteryController;
+ @Mock
+ ConfigurationController mConfigurationController;
private KeyguardClockSwitchController mController;
+ private View mStatusArea;
@Before
public void setup() {
@@ -108,10 +116,13 @@
when(mView.findViewById(R.id.left_aligned_notification_icon_container))
.thenReturn(mNotificationIcons);
+ when(mNotificationIcons.getLayoutParams()).thenReturn(
+ mock(RelativeLayout.LayoutParams.class));
when(mView.getContext()).thenReturn(getContext());
when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
+ when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
when(mClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext());
@@ -131,10 +142,15 @@
mPluginManager,
mFeatureFlags,
mExecutor,
- mBatteryController);
+ mBatteryController,
+ mConfigurationController);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
+
+ mStatusArea = mock(View.class);
+ when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
+
}
@Test
@@ -197,39 +213,40 @@
public void testSmartspacePluginConnectedRemovesKeyguardStatusArea() {
mController.init();
- View statusArea = mock(View.class);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
-
- View nic = mock(View.class);
- when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
- when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
-
BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
TestView view = mock(TestView.class);
when(plugin.getView(any())).thenReturn(view);
mController.mPluginListener.onPluginConnected(plugin, mContext);
- verify(statusArea).setVisibility(View.GONE);
+ verify(mStatusArea).setVisibility(View.GONE);
}
@Test
public void testSmartspacePluginDisconnectedShowsKeyguardStatusArea() {
mController.init();
- View statusArea = mock(View.class);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(statusArea);
-
- View nic = mock(View.class);
- when(mView.findViewById(R.id.left_aligned_notification_icon_container)).thenReturn(nic);
- when(nic.getLayoutParams()).thenReturn(mock(RelativeLayout.LayoutParams.class));
-
BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
TestView view = mock(TestView.class);
when(plugin.getView(any())).thenReturn(view);
mController.mPluginListener.onPluginConnected(plugin, mContext);
mController.mPluginListener.onPluginDisconnected(plugin);
- verify(statusArea).setVisibility(View.VISIBLE);
+ verify(mStatusArea).setVisibility(View.VISIBLE);
+ }
+
+ @Test
+ public void testThemeChangeNotifiesSmartspace() {
+ mController.init();
+
+ BcSmartspaceDataPlugin plugin = mock(BcSmartspaceDataPlugin.class);
+ TestView view = mock(TestView.class);
+ when(plugin.getView(any())).thenReturn(view);
+
+ mController.mPluginListener.onPluginConnected(plugin, mContext);
+
+ reset(view);
+ mController.getConfigurationListener().onThemeChanged();
+ verify(view).setPrimaryTextColor(anyInt());
}
private void verifyAttachment(VerificationMode times) {
@@ -246,5 +263,7 @@
}
public void registerDataProvider(BcSmartspaceDataPlugin plugin) { }
+
+ public void setPrimaryTextColor(int color) { }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index d544f73..42cc1fa9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -49,7 +49,6 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.face.FaceManager;
@@ -188,8 +187,7 @@
when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
doAnswer(invocation -> {
IBiometricEnabledOnKeyguardCallback callback = invocation.getArgument(0);
- callback.onChanged(BiometricSourceType.FACE, true /* enabled */,
- KeyguardUpdateMonitor.getCurrentUser());
+ callback.onChanged(true /* enabled */, KeyguardUpdateMonitor.getCurrentUser());
return null;
}).when(mBiometricManager).registerEnabledOnKeyguardCallback(any());
when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -495,6 +493,11 @@
}
private void testFingerprintWhenStrongAuth(int strongAuth) {
+ // Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
+ // will trigger updateBiometricListeningState();
+ clearInvocations(mFingerprintManager);
+ mKeyguardUpdateMonitor.resetBiometricListeningState();
+
when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
@@ -537,7 +540,7 @@
authCallback.onAuthenticationFailed();
// THEN aod interrupt is cancelled
- verify(mAuthController).onCancelAodInterrupt();
+ verify(mAuthController).onCancelUdfps();
}
@Test
@@ -557,7 +560,7 @@
authCallback.onAuthenticationError(0, "");
// THEN aod interrupt is cancelled
- verify(mAuthController).onCancelAodInterrupt();
+ verify(mAuthController).onCancelUdfps();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index bbd3ce8..0aa182f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -259,7 +259,7 @@
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
// WHEN it is cancelled
- mUdfpsController.onCancelAodInterrupt();
+ mUdfpsController.onCancelUdfps();
// THEN the illumination is hidden
verify(mUdfpsView).stopIllumination();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index acedf59..4f88599 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -81,7 +81,7 @@
mTestableLooper.runWithLooper(() -> {
mQsPanel = new QSPanel(mContext, null);
- mQsPanel.initialize(false);
+ mQsPanel.initialize();
mQsPanel.onFinishInflate();
// Provides a parent with non-zero size for QSPanel
mParentView = new FrameLayout(mContext);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index 62cc9b7..3d53062 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -49,7 +49,7 @@
MockitoAnnotations.initMocks(this);
TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
- new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake(), /* qsFlag */false));
+ new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake()));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
index 87a7757..c2e58ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
@@ -19,6 +19,7 @@
import static junit.framework.Assert.assertEquals;
import android.graphics.Color;
+import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.testing.AndroidTestingRunner;
@@ -89,4 +90,17 @@
mView.setTint(tint);
assertEquals(mView.getTint(), tint);
}
+
+ @Test
+ public void setDrawableBounds_propagatesToDrawable() {
+ ColorDrawable drawable = new ColorDrawable();
+ Rect expectedBounds = new Rect(100, 100, 100, 100);
+ mView.setDrawable(drawable);
+ mView.setDrawableBounds(100, 100, 100, 100);
+
+ assertEquals(expectedBounds, drawable.getBounds());
+ // set bounds that are different from expected drawable bounds
+ mView.onLayout(true, 200, 200, 200, 200);
+ assertEquals(expectedBounds, drawable.getBounds());
+ }
}
diff --git a/services/Android.bp b/services/Android.bp
index ad1406c..20b89de 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -65,6 +65,7 @@
":services.texttospeech-sources",
":services.usage-sources",
":services.usb-sources",
+ ":services.uwb-sources",
":services.voiceinteraction-sources",
":services.wifi-sources",
],
@@ -129,6 +130,7 @@
"services.texttospeech",
"services.usage",
"services.usb",
+ "services.uwb",
"services.voiceinteraction",
"services.wifi",
"service-blobstore",
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a230f80..f8b770b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -456,6 +456,12 @@
} : null;
}
+ void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
+ mPendingFillRequest = null;
+ mWaitForInlineRequest = inlineRequest != null;
+ mPendingInlineSuggestionsRequest = inlineRequest;
+ }
+
void maybeRequestFillLocked() {
if (mPendingFillRequest == null) {
return;
@@ -886,6 +892,11 @@
}
// Now request the assist structure data.
+ requestAssistStructureLocked(requestId, flags);
+ }
+
+ @GuardedBy("mLock")
+ private void requestAssistStructureLocked(int requestId, int flags) {
try {
final Bundle receiverExtras = new Bundle();
receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
@@ -1052,12 +1063,13 @@
if (requestLog != null) {
requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
}
- processNullResponseLocked(requestId, requestFlags);
+ processNullResponseOrFallbackLocked(requestId, requestFlags);
return;
}
fieldClassificationIds = response.getFieldClassificationIds();
- if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
+ if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
+ && !mService.isFieldClassificationEnabledLocked()) {
Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
processNullResponseLocked(requestId, requestFlags);
return;
@@ -1136,6 +1148,26 @@
}
}
+ @GuardedBy("mLock")
+ private void processNullResponseOrFallbackLocked(int requestId, int flags) {
+ if (!mSessionFlags.mClientSuggestionsEnabled) {
+ processNullResponseLocked(requestId, flags);
+ return;
+ }
+
+ // fallback to the default platform password manager
+ mSessionFlags.mClientSuggestionsEnabled = false;
+
+ final InlineSuggestionsRequest inlineRequest =
+ (mLastInlineSuggestionsRequest != null
+ && mLastInlineSuggestionsRequest.first == requestId)
+ ? mLastInlineSuggestionsRequest.second : null;
+ mAssistReceiver.newAutofillRequestLocked(inlineRequest);
+ requestAssistStructureLocked(requestId,
+ flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
+ return;
+ }
+
// FillServiceCallbacks
@Override
public void onFillRequestFailure(int requestId, @Nullable CharSequence message) {
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index c49b8e8..78610a2 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -138,6 +138,8 @@
private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data";
private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY =
"latency_observer_sampling_interval";
+ private static final String SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY =
+ "latency_observer_push_interval_minutes";
private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY =
"latency_histogram_bucket_count";
private static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY =
@@ -218,7 +220,9 @@
mParser.getFloat(
SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY,
BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT));
-
+ binderLatencyObserver.setPushInterval(mParser.getInt(
+ SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY,
+ BinderLatencyObserver.STATSD_PUSH_INTERVAL_MINUTES_DEFAULT));
final boolean enabled =
mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);
diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
index aa56da5..197321f 100644
--- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
+++ b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.RequiresPermission;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
@@ -106,6 +107,7 @@
}
@VisibleForTesting
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
void handleAirplaneModeChange() {
if (shouldSkipAirplaneModeChange()) {
Log.i(TAG, "Ignore airplane mode change");
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 09cfac0..feed220 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -23,6 +23,8 @@
import static android.os.UserHandle.USER_SYSTEM;
import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -304,6 +306,19 @@
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
"Need BLUETOOTH_PRIVILEGED permission");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return onFactoryResetInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
+ private boolean onFactoryResetInternal() {
// Wait for stable state if bluetooth is temporary state.
int state = getState();
if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
@@ -343,6 +358,7 @@
return false;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void onAirplaneModeChanged() {
synchronized (this) {
if (isBluetoothPersistedStateOn()) {
@@ -707,9 +723,6 @@
}
public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (!checkConnectPermissionForPreflight(mContext)) {
- return;
- }
if (callback == null) {
Slog.w(TAG, "registerStateChangeCallback: Callback is null!");
return;
@@ -720,9 +733,6 @@
}
public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (!checkConnectPermissionForPreflight(mContext)) {
- return;
- }
if (callback == null) {
Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!");
return;
@@ -935,6 +945,7 @@
return appCount;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean checkBluetoothPermissions(String packageName, boolean requireForeground) {
if (isBluetoothDisallowed()) {
if (DBG) {
@@ -990,6 +1001,7 @@
return true;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean disableBle(String packageName, IBinder token) throws RemoteException {
if (!checkBluetoothPermissions(packageName, false)) {
if (DBG) {
@@ -1040,6 +1052,7 @@
* Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on,
* call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
private void continueFromBleOnState() {
if (DBG) {
Slog.d(TAG, "continueFromBleOnState()");
@@ -1072,6 +1085,10 @@
* Inform BluetoothAdapter instances that BREDR part is down
* and turn off all service and stack if no LE app needs it
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
private void sendBrEdrDownCallback() {
if (DBG) {
Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks");
@@ -1265,12 +1282,14 @@
*
* @hide
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private boolean checkBluetoothPermissionWhenWirelessConsentRequired() {
int result = mContext.checkCallingPermission(
android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED);
return result == PackageManager.PERMISSION_GRANTED;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void unbindAndFinish() {
if (DBG) {
Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding
@@ -2300,6 +2319,10 @@
}
}
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED
+ })
private void restartForReason(int reason) {
try {
mBluetoothLock.readLock().lock();
@@ -2376,6 +2399,7 @@
}
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void handleEnable(boolean quietMode) {
mQuietEnable = quietMode;
@@ -2418,6 +2442,7 @@
return true;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void handleDisable() {
try {
mBluetoothLock.readLock().lock();
@@ -2475,6 +2500,10 @@
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_CONNECT);
}
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
private void bluetoothStateChangeHandler(int prevState, int newState) {
boolean isStandardBroadcast = true;
if (prevState == newState) { // No change. Nothing to do.
@@ -2615,6 +2644,10 @@
}
}
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
private void recoverBluetoothServiceFromError(boolean clearBle) {
Slog.e(TAG, "recoverBluetoothServiceFromError");
try {
@@ -2848,6 +2881,7 @@
*
* <p>Should be used in situations where the app op should not be noted.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private static boolean checkConnectPermissionForPreflight(Context context) {
int permissionCheckResult = PermissionChecker.checkCallingOrSelfPermissionForPreflight(
context, BLUETOOTH_CONNECT);
diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
index 242fa84..3642e4d 100644
--- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java
+++ b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHearingAid;
@@ -101,6 +102,7 @@
}
@VisibleForTesting
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void onAirplaneModeChanged(BluetoothManagerService managerService) {
managerService.onAirplaneModeChanged();
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d9cc4b4..4d96162 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1353,8 +1353,8 @@
new NetworkInfo(TYPE_NONE, 0, "", ""),
new LinkProperties(), new NetworkCapabilities(),
new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
- new NetworkAgentConfig(), this, null, null, 0, INVALID_UID, mQosCallbackTracker,
- mDeps);
+ new NetworkAgentConfig(), this, null, null, 0, INVALID_UID,
+ mLingerDelayMs, mQosCallbackTracker, mDeps);
}
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -3167,6 +3167,11 @@
} else {
logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
}
+ break;
+ }
+ case NetworkAgent.EVENT_LINGER_DURATION_CHANGED: {
+ nai.setLingerDuration((int) arg.second);
+ break;
}
}
}
@@ -6516,7 +6521,8 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker, mDeps);
+ this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,
+ mQosCallbackTracker, mDeps);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
processCapabilitiesFromAgent(nai, nc);
@@ -7759,7 +7765,7 @@
log(" accepting network in place of " + previousSatisfier.toShortString());
}
previousSatisfier.removeRequest(previousRequest.requestId);
- previousSatisfier.lingerRequest(previousRequest.requestId, now, mLingerDelayMs);
+ previousSatisfier.lingerRequest(previousRequest.requestId, now);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 9f91dd6..483250a 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -174,9 +174,9 @@
# Disk usage stats for verifying quota correctness
3121 pm_package_stats (manual_time|2|3),(quota_time|2|3),(manual_data|2|2),(quota_data|2|2),(manual_cache|2|2),(quota_cache|2|2)
# Snapshot statistics
-3130 pm_snapshot_stats (build_count|1|1),(reuse_count|1|1),(big_builds|1|1),(quick_rebuilds|1|1),(max_build_time|1|3),(cumm_build_time|1|3)
+3130 pm_snapshot_stats (build_count|1|1),(reuse_count|1|1),(big_builds|1|1),(short_lived|1|1),(max_build_time|1|3),(cumm_build_time|2|3)
# Snapshot rebuild instance
-3131 pm_snapshot_rebuild (build_time|1|3),(elapsed|1|3)
+3131 pm_snapshot_rebuild (build_time|1|3),(lifetime|1|3)
# ---------------------------
# InputMethodManagerService.java
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index df6ab5d..3ba4c34 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -19,9 +19,10 @@
import static android.Manifest.permission.MANAGE_SENSOR_PRIVACY;
import static android.app.ActivityManager.RunningServiceInfo;
import static android.app.ActivityManager.RunningTaskInfo;
-import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.SensorPrivacyManager.EXTRA_SENSOR;
@@ -140,11 +141,15 @@
private final UserManagerInternal mUserManagerInternal;
private final ActivityManager mActivityManager;
private final ActivityTaskManager mActivityTaskManager;
+ private final AppOpsManager mAppOpsManager;
+
+ private final IBinder mAppOpsRestrictionToken = new Binder();
private SensorPrivacyManagerInternalImpl mSensorPrivacyManagerInternal;
public SensorPrivacyService(Context context) {
super(context);
+ mAppOpsManager = context.getSystemService(AppOpsManager.class);
mUserManagerInternal = getLocalService(UserManagerInternal.class);
mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl(context);
mActivityManager = context.getSystemService(ActivityManager.class);
@@ -194,10 +199,20 @@
}
}
+ for (int i = 0; i < mIndividualEnabled.size(); i++) {
+ int userId = mIndividualEnabled.keyAt(i);
+ SparseBooleanArray userIndividualEnabled =
+ mIndividualEnabled.get(i);
+ for (int j = 0; j < userIndividualEnabled.size(); j++) {
+ int sensor = userIndividualEnabled.keyAt(i);
+ boolean enabled = userIndividualEnabled.valueAt(j);
+ setUserRestriction(userId, sensor, enabled);
+ }
+ }
+
int[] micAndCameraOps = new int[]{OP_RECORD_AUDIO, OP_CAMERA};
- AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
- appOpsManager.startWatchingNoted(micAndCameraOps, this);
- appOpsManager.startWatchingStarted(micAndCameraOps, this);
+ mAppOpsManager.startWatchingNoted(micAndCameraOps, this);
+ mAppOpsManager.startWatchingStarted(micAndCameraOps, this);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
@@ -221,7 +236,7 @@
public void onOpNoted(int code, int uid, String packageName,
String attributionTag, @AppOpsManager.OpFlags int flags,
@AppOpsManager.Mode int result) {
- if (result != MODE_ALLOWED || (flags & AppOpsManager.OP_FLAGS_ALL_TRUSTED) == 0) {
+ if (result != MODE_IGNORED || (flags & AppOpsManager.OP_FLAGS_ALL_TRUSTED) == 0) {
return;
}
@@ -1125,6 +1140,9 @@
mSensorPrivacyManagerInternal.dispatch(userId, sensor, enabled);
SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
mIndividualSensorListeners.get(userId);
+
+ setUserRestriction(userId, sensor, enabled);
+
if (listenersForUser == null) {
return;
}
@@ -1152,6 +1170,18 @@
}
}
+ private void setUserRestriction(int userId, int sensor, boolean enabled) {
+ if (sensor == CAMERA) {
+ mAppOpsManager.setUserRestrictionForUser(OP_CAMERA, enabled,
+ mAppOpsRestrictionToken, new String[]{}, userId);
+ } else if (sensor == MICROPHONE) {
+ mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO, enabled,
+ mAppOpsRestrictionToken, new String[]{}, userId);
+ mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO_HOTWORD, enabled,
+ mAppOpsRestrictionToken, new String[]{}, userId);
+ }
+ }
+
private final class DeathRecipient implements IBinder.DeathRecipient {
private ISensorPrivacyListener mListener;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 611fe7a..2d486c4 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -376,7 +376,7 @@
private final LocalLog mListenLog = new LocalLog(200);
- private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
+ private List<List<PhysicalChannelConfig>> mPhysicalChannelConfigs;
private boolean[] mIsDataEnabled;
@@ -716,7 +716,7 @@
mTelephonyDisplayInfos[i] = null;
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
- mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+ mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
mLinkCapacityEstimateLists.add(i, new ArrayList<>());
@@ -816,7 +816,7 @@
mTelephonyDisplayInfos[i] = null;
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
- mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+ mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
mLinkCapacityEstimateLists.add(i, new ArrayList<>());
@@ -1314,8 +1314,9 @@
try {
r.callback.onPhysicalChannelConfigChanged(
shouldSanitizeLocationForPhysicalChannelConfig(r)
- ? getLocationSanitizedConfigs(mPhysicalChannelConfigs)
- : mPhysicalChannelConfigs);
+ ? getLocationSanitizedConfigs(
+ mPhysicalChannelConfigs.get(phoneId))
+ : mPhysicalChannelConfigs.get(phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -2550,11 +2551,12 @@
* Send a notification to registrants that the configs of physical channel has changed for
* a particular subscription.
*
+ * @param phoneId the phone id.
* @param subId the subId
* @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
*/
- public void notifyPhysicalChannelConfigForSubscriber(
- int subId, List<PhysicalChannelConfig> configs) {
+ public void notifyPhysicalChannelConfigForSubscriber(int phoneId, int subId,
+ List<PhysicalChannelConfig> configs) {
if (!checkNotifyPermission("notifyPhysicalChannelConfig()")) {
return;
}
@@ -2566,9 +2568,8 @@
}
synchronized (mRecords) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
- mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId));
+ mPhysicalChannelConfigs.set(phoneId, configs);
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
@@ -2775,6 +2776,7 @@
pw.println("mDataEnabledReason=" + mDataEnabledReason);
pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]);
pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]);
+ pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i));
pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i));
pw.decreaseIndent();
}
@@ -2785,7 +2787,6 @@
pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.println("mDefaultPhoneId=" + mDefaultPhoneId);
pw.println("mDefaultSubId=" + mDefaultSubId);
- pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs);
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 3b31ab2..039f4d9 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -362,8 +362,7 @@
/** Notifies the VcnManagementService that external dependencies can be set up. */
public void systemReady() {
- mContext.getSystemService(ConnectivityManager.class)
- .registerNetworkProvider(mNetworkProvider);
+ mNetworkProvider.register();
mContext.getSystemService(ConnectivityManager.class)
.registerNetworkCallback(
new NetworkRequest.Builder().clearCapabilities().build(),
@@ -935,13 +934,31 @@
pw.println("VcnManagementService dump:");
pw.increaseIndent();
+ pw.println("mNetworkProvider:");
+ pw.increaseIndent();
mNetworkProvider.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
+
+ pw.println("mTrackingNetworkCallback:");
+ pw.increaseIndent();
+ mTrackingNetworkCallback.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
synchronized (mLock) {
+ pw.println("mLastSnapshot:");
+ pw.increaseIndent();
+ mLastSnapshot.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
+
pw.println("mVcns:");
+ pw.increaseIndent();
for (Vcn vcn : mVcns.values()) {
vcn.dump(pw);
}
+ pw.decreaseIndent();
pw.println();
}
@@ -1003,6 +1020,24 @@
return false;
}
+
+ /** Dumps the state of this snapshot for logging and debugging purposes. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("TrackingNetworkCallback:");
+ pw.increaseIndent();
+
+ pw.println("mCaps:");
+ pw.increaseIndent();
+ synchronized (mCaps) {
+ for (Entry<Network, NetworkCapabilities> entry : mCaps.entrySet()) {
+ pw.println(entry.getKey() + ": " + entry.getValue());
+ }
+ }
+ pw.decreaseIndent();
+ pw.println();
+
+ pw.decreaseIndent();
+ }
}
/** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 50040e2..4324717 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1792,6 +1792,9 @@
showFgsBgRestrictedNotificationLocked(r);
updateServiceForegroundLocked(psr, true);
ignoreForeground = true;
+ logForegroundServiceStateChanged(r,
+ FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED,
+ 0);
if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID,
r.appInfo.uid)) {
throw new ForegroundServiceStartNotAllowedException(msg);
@@ -1837,6 +1840,7 @@
}
r.isForeground = true;
r.mStartForegroundCount++;
+ r.mFgsEnterTime = SystemClock.uptimeMillis();
if (!stopProcStatsOp) {
ServiceState stracker = r.getTracker();
if (stracker != null) {
@@ -1846,18 +1850,17 @@
} else {
stopProcStatsOp = false;
}
+ postFgsNotificationLocked(r);
mAm.mAppOpsService.startOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName,
null, true, false, "", false);
- FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
- r.appInfo.uid, r.shortInstanceName,
+ logForegroundServiceStateChanged(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
- r.mAllowWhileInUsePermissionInFgs);
+ 0);
registerAppOpCallbackLocked(r);
mAm.updateForegroundServiceUsageStats(r.name, r.userId, true);
}
- postFgsNotificationLocked(r);
if (r.app != null) {
updateServiceForegroundLocked(psr, true);
}
@@ -1896,6 +1899,7 @@
}
r.isForeground = false;
resetFgsRestrictionLocked(r);
+ r.mFgsExitTime = SystemClock.uptimeMillis();
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -1905,10 +1909,10 @@
AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
unregisterAppOpCallbackLocked(r);
- FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
- r.appInfo.uid, r.shortInstanceName,
+ logForegroundServiceStateChanged(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
- r.mAllowWhileInUsePermissionInFgs);
+ r.mFgsExitTime > r.mFgsEnterTime
+ ? (int)(r.mFgsExitTime - r.mFgsEnterTime) : 0);
mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
if (r.app != null) {
mAm.updateLruProcessLocked(r.app, false, null);
@@ -1992,9 +1996,13 @@
Slog.d(TAG_SERVICE, "FGS " + r + " non-deferred notification");
}
r.postNotification();
+ r.mFgsNotificationDeferred = false;
+ r.mFgsNotificationShown = true;
return;
}
+ r.mFgsNotificationDeferred = true;
+ r.mFgsNotificationShown = false;
// schedule the actual notification post
long when = now + mAm.mConstants.mFgsNotificationDeferralInterval;
// If there are already deferred FGS notifications for this app,
@@ -2052,6 +2060,7 @@
// the notification.
if (r.isForeground && r.app != null) {
r.postNotification();
+ r.mFgsNotificationShown = true;
} else if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, " - service no longer running/fg, ignoring");
}
@@ -3027,6 +3036,12 @@
if (r != null) {
r.mRecentCallingPackage = callingPackage;
r.mRecentCallingUid = callingUid;
+ try {
+ r.mRecentCallerApplicationInfo =
+ mAm.mContext.getPackageManager().getApplicationInfoAsUser(callingPackage,
+ 0, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ }
if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName,
r.appInfo.uid)) {
String msg = "association not allowed between packages "
@@ -3963,10 +3978,11 @@
AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
unregisterAppOpCallbackLocked(r);
- FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
- r.appInfo.uid, r.shortInstanceName,
+ r.mFgsExitTime = SystemClock.uptimeMillis();
+ logForegroundServiceStateChanged(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT,
- r.mAllowWhileInUsePermissionInFgs);
+ r.mFgsExitTime > r.mFgsEnterTime
+ ? (int)(r.mFgsExitTime - r.mFgsEnterTime) : 0);
mAm.updateForegroundServiceUsageStats(r.name, r.userId, false);
}
@@ -5880,4 +5896,29 @@
r.mLoggedInfoAllowStartForeground = true;
}
}
+
+ /**
+ * Log the statsd event for FGS.
+ * @param r ServiceRecord
+ * @param state one of ENTER/EXIT/DENIED event.
+ * @param durationMs Only meaningful for EXIT event, the duration from ENTER and EXIT state.
+ */
+ private void logForegroundServiceStateChanged(ServiceRecord r, int state, int durationMs) {
+ FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
+ r.appInfo.uid,
+ r.shortInstanceName,
+ state,
+ r.mAllowWhileInUsePermissionInFgs,
+ r.mAllowStartForeground,
+ r.appInfo.targetSdkVersion,
+ r.mRecentCallingUid,
+ r.mRecentCallerApplicationInfo != null
+ ? r.mRecentCallerApplicationInfo.targetSdkVersion : 0,
+ r.mInfoTempFgsAllowListReason != null
+ ? r.mInfoTempFgsAllowListReason.mCallingUid : INVALID_UID,
+ r.mFgsNotificationDeferred,
+ r.mFgsNotificationShown,
+ durationMs,
+ r.mStartForegroundCount);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2a1a897..e3b06d6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2500,7 +2500,7 @@
@Override
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
- broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
+ broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null, null,
OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
@@ -3940,7 +3940,7 @@
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.getUserId(uid));
}
@@ -7531,7 +7531,7 @@
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, null, intent,
- null, null, 0, null, null, null, OP_NONE,
+ null, null, 0, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
@@ -7543,8 +7543,8 @@
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) {}
- }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, OP_NONE, null,
- true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
UserHandle.USER_ALL);
} catch (Throwable e) {
Slog.wtf(TAG, "Failed sending first user broadcasts", e);
@@ -12302,7 +12302,7 @@
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, null, -1, -1, false, null, null, OP_NONE, null, receivers,
+ null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
@@ -12544,13 +12544,13 @@
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
- int realCallingPid, int userId) {
+ Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions,
+ int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid,
+ int callingUid, int realCallingUid, int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
- appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
- realCallingPid, userId, false /* allowBackgroundActivityStarts */,
+ excludedPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid,
+ realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */,
null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}
@@ -12558,9 +12558,11 @@
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
- int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
+ Bundle resultExtras, String[] requiredPermissions,
+ String[] excludedPermissions, int appOp, Bundle bOptions,
+ boolean ordered, boolean sticky, int callingPid, int callingUid,
+ int realCallingUid, int realCallingPid, int userId,
+ boolean allowBackgroundActivityStarts,
@Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastAllowList) {
intent = new Intent(intent);
@@ -13139,8 +13141,8 @@
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
- resultCode, resultData, resultExtras, ordered, sticky, false, userId,
+ requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
+ resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, backgroundActivityStartsToken,
timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
@@ -13237,10 +13239,10 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
- resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts, backgroundActivityStartsToken,
- timeoutExempt);
+ requiredPermissions, excludedPermissions, appOp, brOptions,
+ receivers, resultTo, resultCode, resultData, resultExtras,
+ ordered, sticky, false, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
@@ -13366,14 +13368,14 @@
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
return broadcastIntentWithFeature(caller, null, intent, resolvedType, resultTo, resultCode,
- resultData, resultExtras, requiredPermissions, appOp, bOptions, serialized, sticky,
- userId);
+ resultData, resultExtras, requiredPermissions, null, appOp, bOptions, serialized,
+ sticky, userId);
}
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
- String[] requiredPermissions, int appOp, Bundle bOptions,
+ String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
@@ -13388,8 +13390,8 @@
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, appOp, bOptions, serialized, sticky,
- callingPid, callingUid, callingUid, callingPid, userId);
+ requiredPermissions, excludedPermissions, appOp, bOptions, serialized,
+ sticky, callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -13410,7 +13412,7 @@
: new String[] {requiredPermission};
try {
return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
- resultTo, resultCode, resultData, resultExtras, requiredPermissions,
+ resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken,
@@ -15615,7 +15617,7 @@
return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/,
null /*callerPackage*/, null /*callingFeatureId*/, intent,
null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/,
- null /*resultExtras*/, requiredPermissions, AppOpsManager.OP_NONE,
+ null /*resultExtras*/, requiredPermissions, null, AppOpsManager.OP_NONE,
bOptions /*options*/, serialized, false /*sticky*/, callingPid,
callingUid, callingUid, callingPid, userId,
false /*allowBackgroundStarts*/,
@@ -15740,8 +15742,8 @@
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.USER_ALL);
+ null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
@@ -15751,8 +15753,9 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
- Binder.getCallingPid(), UserHandle.USER_ALL);
+ null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ UserHandle.USER_ALL);
}
// Send a broadcast to PackageInstallers if the configuration change is interesting
@@ -15766,7 +15769,7 @@
String[] permissions =
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null,
- permissions, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ permissions, null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -15791,7 +15794,7 @@
}
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ null, OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 42aac29..6fa8ecd4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -760,7 +760,7 @@
pw.flush();
Bundle bundle = mBroadcastOptions == null ? null : mBroadcastOptions.toBundle();
mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, bundle, true, false,
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE, bundle, true, false,
mUserId);
if (!mAsync) {
receiver.waitForFinish();
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 60e8d54..4942b11 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -205,7 +205,7 @@
mPowerStatsInternal = psi;
boolean[] supportedStdBuckets = null;
- int numCustomBuckets = 0;
+ String[] customBucketNames = null;
if (mPowerStatsInternal != null) {
final SparseArray<EnergyConsumer> idToConsumer
= populateEnergyConsumerSubsystemMapsLocked();
@@ -227,12 +227,12 @@
+ e.getCause());
// Continue running, later attempts to query may be successful.
}
- numCustomBuckets = mMeasuredEnergySnapshot.getNumOtherOrdinals();
+ customBucketNames = mMeasuredEnergySnapshot.getOtherOrdinalNames();
supportedStdBuckets = getSupportedEnergyBuckets(idToConsumer);
}
}
synchronized (mStats) {
- mStats.initMeasuredEnergyStatsLocked(supportedStdBuckets, numCustomBuckets);
+ mStats.initMeasuredEnergyStatsLocked(supportedStdBuckets, customBucketNames);
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a5474d0b..f0b116c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1419,6 +1419,7 @@
skip = true;
}
}
+
boolean isSingleton = false;
try {
isSingleton = mService.isSingleton(info.activityInfo.processName,
@@ -1553,6 +1554,37 @@
+ info.activityInfo.applicationInfo.uid + " : user is not running");
}
+ if (!skip && r.excludedPermissions != null && r.excludedPermissions.length > 0) {
+ for (int i = 0; i < r.excludedPermissions.length; i++) {
+ String excludedPermission = r.excludedPermissions[i];
+ try {
+ perm = AppGlobals.getPackageManager()
+ .checkPermission(excludedPermission,
+ info.activityInfo.applicationInfo.packageName,
+ UserHandle
+ .getUserId(info.activityInfo.applicationInfo.uid));
+ } catch (RemoteException e) {
+ perm = PackageManager.PERMISSION_DENIED;
+ }
+
+ if (perm == PackageManager.PERMISSION_GRANTED) {
+ skip = true;
+ break;
+ }
+
+ int appOp = AppOpsManager.permissionToOpCode(excludedPermission);
+ if (appOp != AppOpsManager.OP_NONE) {
+ if (mService.getAppOpsManager().checkOpNoThrow(appOp,
+ info.activityInfo.applicationInfo.uid,
+ info.activityInfo.packageName)
+ == AppOpsManager.MODE_ALLOWED) {
+ skip = true;
+ break;
+ }
+ }
+ }
+ }
+
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 198ba34..8015596 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -62,6 +62,7 @@
final int userId; // user id this broadcast was for
final String resolvedType; // the resolved data type
final String[] requiredPermissions; // permissions the caller has required
+ final String[] excludedPermissions; // permissions to exclude
final int appOp; // an app op that is associated with this broadcast
final BroadcastOptions options; // BroadcastOptions supplied by caller
final List receivers; // contains BroadcastFilter and ResolveInfo
@@ -142,6 +143,10 @@
pw.print(Arrays.toString(requiredPermissions));
pw.print(" appOp="); pw.println(appOp);
}
+ if (excludedPermissions != null && excludedPermissions.length > 0) {
+ pw.print(prefix); pw.print("excludedPermissions=");
+ pw.print(Arrays.toString(excludedPermissions));
+ }
if (options != null) {
pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
}
@@ -240,11 +245,11 @@
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
@Nullable String _callerFeatureId, int _callingPid, int _callingUid,
boolean _callerInstantApp, String _resolvedType,
- String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
- IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
- boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
- boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken,
- boolean timeoutExempt) {
+ String[] _requiredPermissions, String[] _excludedPermissions, int _appOp,
+ BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
+ String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
+ boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken, boolean timeoutExempt) {
if (_intent == null) {
throw new NullPointerException("Can't construct with a null intent");
}
@@ -259,6 +264,7 @@
callerInstantApp = _callerInstantApp;
resolvedType = _resolvedType;
requiredPermissions = _requiredPermissions;
+ excludedPermissions = _excludedPermissions;
appOp = _appOp;
options = _options;
receivers = _receivers;
@@ -299,6 +305,7 @@
userId = from.userId;
resolvedType = from.resolvedType;
requiredPermissions = from.requiredPermissions;
+ excludedPermissions = from.excludedPermissions;
appOp = from.appOp;
options = from.options;
receivers = from.receivers;
@@ -356,8 +363,8 @@
// build a new BroadcastRecord around that single-target list
BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
- requiredPermissions, appOp, options, splitReceivers, resultTo, resultCode,
- resultData, resultExtras, ordered, sticky, initialSticky, userId,
+ requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
+ resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
split.splitToken = this.splitToken;
diff --git a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
index f9296a0..65d4755 100644
--- a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
+++ b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
@@ -99,14 +99,6 @@
mAttributionSnapshots = new SparseArray<>(mNumOtherOrdinals);
}
- /**
- * Returns the number of ordinals for {@link EnergyConsumerType#OTHER}, i.e. the number of
- * custom energy buckets supported by the device.
- */
- public int getNumOtherOrdinals() {
- return mNumOtherOrdinals;
- }
-
/** Class for returning the relevant data calculated from the measured energy delta */
static class MeasuredEnergyDeltaData {
/** The chargeUC for {@link EnergyConsumerType#BLUETOOTH}. */
@@ -147,7 +139,7 @@
* Fields with no interesting data (consumers not present in ecrs or with no energy
* difference) will generally be left as their default values.
* otherTotalChargeUC and otherUidChargesUC are always either both null or both of
- * length {@link #getNumOtherOrdinals()}.
+ * length {@link #getOtherOrdinalNames().length}.
* Returns null, if ecrs is null or empty.
*/
public @Nullable MeasuredEnergyDeltaData updateAndGetDelta(EnergyConsumerResult[] ecrs,
@@ -237,8 +229,8 @@
case EnergyConsumerType.OTHER:
if (output.otherTotalChargeUC == null) {
- output.otherTotalChargeUC = new long[getNumOtherOrdinals()];
- output.otherUidChargesUC = new SparseLongArray[getNumOtherOrdinals()];
+ output.otherTotalChargeUC = new long[mNumOtherOrdinals];
+ output.otherUidChargesUC = new SparseLongArray[mNumOtherOrdinals];
}
output.otherTotalChargeUC[ordinal] = deltaChargeUC;
output.otherUidChargesUC[ordinal] = otherUidCharges;
@@ -342,6 +334,23 @@
pw.println();
}
+ /**
+ * Returns the names of ordinals for {@link EnergyConsumerType#OTHER}, i.e. the names of
+ * custom energy buckets supported by the device.
+ */
+ public String[] getOtherOrdinalNames() {
+ final String[] names = new String[mNumOtherOrdinals];
+ int consumerIndex = 0;
+ final int size = mEnergyConsumers.size();
+ for (int idx = 0; idx < size; idx++) {
+ final EnergyConsumer consumer = mEnergyConsumers.valueAt(idx);
+ if (consumer.type == (int) EnergyConsumerType.OTHER) {
+ names[consumerIndex++] = consumer.name;
+ }
+ }
+ return names;
+ }
+
/** Determines the number of ordinals for a given {@link EnergyConsumerType}. */
private static int calculateNumOrdinals(@EnergyConsumerType int type,
SparseArray<EnergyConsumer> idToConsumer) {
@@ -361,5 +370,4 @@
// since the last snapshot. Round off to the nearest whole long.
return (deltaEnergyUJ * MILLIVOLTS_PER_VOLT + (avgVoltageMV / 2)) / avgVoltageMV;
}
-
}
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 984fe40..7562098 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -124,7 +124,7 @@
REASON_PRE_BOOT_COMPLETED, "");
synchronized (mService) {
mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
- null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
+ null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 54c3512..21a02ed8 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -161,6 +161,17 @@
String mRecentCallingPackage;
// the most recent uid that start/bind this service.
int mRecentCallingUid;
+ // ApplicationInfo of the most recent callingPackage that start/bind this service.
+ @Nullable ApplicationInfo mRecentCallerApplicationInfo;
+
+ // The uptime when the service enters FGS state.
+ long mFgsEnterTime = 0;
+ // The uptime when the service exits FGS state.
+ long mFgsExitTime = 0;
+ // FGS notification was deferred.
+ boolean mFgsNotificationDeferred;
+ // FGS notification was shown before the FGS finishes, or it wasn't deferred in the first place.
+ boolean mFgsNotificationShown;
// allow the service becomes foreground service? Service started from background may not be
// allowed to become a foreground service.
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a5d0e72..ba3e1fb 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2936,8 +2936,8 @@
// TODO b/64165549 Verify that mLock is not held before calling AMS methods
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, null, intent, resolvedType,
- resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp,
- bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
+ resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
+ appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
realCallingPid, userId);
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 419e686..3f07572 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1827,7 +1827,8 @@
}
}
- mHistoricalRegistry.clearHistory(uid, packageName);
+ mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory,
+ mHistoricalRegistry, uid, packageName));
}
public void uidRemoved(int uid) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 282a12d..96bb73f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -503,7 +503,7 @@
}
}
- private static final class BtDeviceConnectionInfo {
+ /*package*/ static final class BtDeviceConnectionInfo {
final @NonNull BluetoothDevice mDevice;
final @AudioService.BtProfileConnectionState int mState;
final int mProfile;
@@ -520,6 +520,14 @@
mVolume = vol;
}
+ BtDeviceConnectionInfo(@NonNull BtDeviceConnectionInfo info) {
+ mDevice = info.mDevice;
+ mState = info.mState;
+ mProfile = info.mProfile;
+ mSupprNoisy = info.mSupprNoisy;
+ mVolume = info.mVolume;
+ }
+
// redefine equality op so we can match messages intended for this device
@Override
public boolean equals(Object o) {
@@ -541,18 +549,19 @@
}
}
- /*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- int profile, boolean suppressNoisyIntent, int a2dpVolume) {
- final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
- suppressNoisyIntent, a2dpVolume);
-
- final String name = TextUtils.emptyIfNull(device.getName());
+ /**
+ * will block on mDeviceStateLock, which is held during an A2DP (dis) connection
+ * not just a simple message post
+ * @param info struct with the (dis)connection information
+ */
+ /*package*/ void queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ @NonNull BtDeviceConnectionInfo info) {
+ final String name = TextUtils.emptyIfNull(info.mDevice.getName());
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
+ "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
- .set(MediaMetrics.Property.STATE, state == BluetoothProfile.STATE_CONNECTED
+ .set(MediaMetrics.Property.STATE, info.mState == BluetoothProfile.STATE_CONNECTED
? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
- .set(MediaMetrics.Property.INDEX, a2dpVolume)
+ .set(MediaMetrics.Property.INDEX, info.mVolume)
.set(MediaMetrics.Property.NAME, name)
.record();
@@ -562,10 +571,10 @@
// when receiving a request to change the connection state of a device, this last
// request is the source of truth, so cancel all previous requests that are already in
// the handler
- removeScheduledA2dpEvents(device);
+ removeScheduledA2dpEvents(info.mDevice);
sendLMsgNoDelay(
- state == BluetoothProfile.STATE_CONNECTED
+ info.mState == BluetoothProfile.STATE_CONNECTED
? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
: MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
SENDMSG_QUEUE, info);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9707ace..edacd40 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -310,6 +310,8 @@
private static final int MSG_UPDATE_A11Y_SERVICE_UIDS = 35;
private static final int MSG_UPDATE_AUDIO_MODE = 36;
private static final int MSG_RECORDING_CONFIG_CHANGE = 37;
+ private static final int MSG_SET_A2DP_DEV_CONNECTION_STATE = 38;
+ private static final int MSG_A2DP_DEV_CONFIG_CHANGE = 39;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
@@ -6114,7 +6116,7 @@
* See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent()
*/
public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
+ @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
int profile, boolean suppressNoisyIntent, int a2dpVolume) {
if (device == null) {
throw new IllegalArgumentException("Illegal null device");
@@ -6124,8 +6126,13 @@
throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
+ " (dis)connection, got " + state);
}
- mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, state,
- profile, suppressNoisyIntent, a2dpVolume);
+
+ AudioDeviceBroker.BtDeviceConnectionInfo info =
+ new AudioDeviceBroker.BtDeviceConnectionInfo(device, state,
+ profile, suppressNoisyIntent, a2dpVolume);
+ sendMsg(mAudioHandler, MSG_SET_A2DP_DEV_CONNECTION_STATE, SENDMSG_QUEUE,
+ 0 /*arg1*/, 0 /*arg2*/,
+ /*obj*/ info, 0 /*delay*/);
}
/** only public for mocking/spying, do not call outside of AudioService */
@@ -6143,7 +6150,8 @@
if (device == null) {
throw new IllegalArgumentException("Illegal null device");
}
- mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
+ sendMsg(mAudioHandler, MSG_A2DP_DEV_CONFIG_CHANGE, SENDMSG_QUEUE, 0, 0,
+ /*obj*/ device, /*delay*/ 0);
}
private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET;
@@ -7505,6 +7513,15 @@
onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj, false /*force*/);
}
break;
+
+ case MSG_SET_A2DP_DEV_CONNECTION_STATE:
+ mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ (AudioDeviceBroker.BtDeviceConnectionInfo) msg.obj);
+ break;
+
+ case MSG_A2DP_DEV_CONFIG_CHANGE:
+ mDeviceBroker.postBluetoothA2dpDeviceConfigChange((BluetoothDevice) msg.obj);
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index c57d5af..52e8edf 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -454,8 +454,10 @@
}
final BluetoothDevice btDevice = deviceList.get(0);
// the device is guaranteed CONNECTED
- mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(btDevice,
- BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK, true, -1);
+ mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ new AudioDeviceBroker.BtDeviceConnectionInfo(btDevice,
+ BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK,
+ true, -1));
}
/*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index cb7c568..a546a60 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -35,7 +35,6 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -51,6 +50,7 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
@@ -338,18 +338,31 @@
private static final boolean DEFAULT_APP_ENABLED = true;
private static final boolean DEFAULT_ALWAYS_REQUIRE_CONFIRMATION = false;
+ // Some devices that shipped before S already have face-specific settings. Instead of
+ // migrating, which is complicated, let's just keep using the existing settings.
+ private final boolean mUseLegacyFaceOnlySettings;
+
+ // Only used for legacy face-only devices
private final Uri FACE_UNLOCK_KEYGUARD_ENABLED =
Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED);
private final Uri FACE_UNLOCK_APP_ENABLED =
Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_APP_ENABLED);
+
+ // Continues to be used, even though it's face-specific.
private final Uri FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
+ // Used for all devices other than legacy face-only devices
+ private final Uri BIOMETRIC_KEYGUARD_ENABLED =
+ Settings.Secure.getUriFor(Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED);
+ private final Uri BIOMETRIC_APP_ENABLED =
+ Settings.Secure.getUriFor(Settings.Secure.BIOMETRIC_APP_ENABLED);
+
private final ContentResolver mContentResolver;
private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks;
- private final Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>();
- private final Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>();
+ private final Map<Integer, Boolean> mBiometricEnabledOnKeyguard = new HashMap<>();
+ private final Map<Integer, Boolean> mBiometricEnabledForApps = new HashMap<>();
private final Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>();
/**
@@ -362,21 +375,44 @@
super(handler);
mContentResolver = context.getContentResolver();
mCallbacks = callbacks;
+
+ final boolean hasFingerprint = context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+ final boolean hasFace = context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_FACE);
+
+ // Use the legacy setting on face-only devices that shipped on or before Q
+ mUseLegacyFaceOnlySettings =
+ Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.Q
+ && hasFace && !hasFingerprint;
+
updateContentObserver();
}
public void updateContentObserver() {
mContentResolver.unregisterContentObserver(this);
- mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
- false /* notifyForDescendents */,
- this /* observer */,
- UserHandle.USER_ALL);
- mContentResolver.registerContentObserver(FACE_UNLOCK_APP_ENABLED,
- false /* notifyForDescendents */,
- this /* observer */,
- UserHandle.USER_ALL);
+
+ if (mUseLegacyFaceOnlySettings) {
+ mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(FACE_UNLOCK_APP_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ } else {
+ mContentResolver.registerContentObserver(BIOMETRIC_KEYGUARD_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(BIOMETRIC_APP_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
+ }
mContentResolver.registerContentObserver(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
- false /* notifyForDescendents */,
+ false /* notifyForDescendants */,
this /* observer */,
UserHandle.USER_ALL);
}
@@ -384,7 +420,7 @@
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
if (FACE_UNLOCK_KEYGUARD_ENABLED.equals(uri)) {
- mFaceEnabledOnKeyguard.put(userId, Settings.Secure.getIntForUser(
+ mBiometricEnabledOnKeyguard.put(userId, Settings.Secure.getIntForUser(
mContentResolver,
Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED,
DEFAULT_KEYGUARD_ENABLED ? 1 : 0 /* default */,
@@ -394,7 +430,7 @@
notifyEnabledOnKeyguardCallbacks(userId);
}
} else if (FACE_UNLOCK_APP_ENABLED.equals(uri)) {
- mFaceEnabledForApps.put(userId, Settings.Secure.getIntForUser(
+ mBiometricEnabledForApps.put(userId, Settings.Secure.getIntForUser(
mContentResolver,
Settings.Secure.FACE_UNLOCK_APP_ENABLED,
DEFAULT_APP_ENABLED ? 1 : 0 /* default */,
@@ -405,22 +441,45 @@
Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
DEFAULT_ALWAYS_REQUIRE_CONFIRMATION ? 1 : 0 /* default */,
userId) != 0);
+ } else if (BIOMETRIC_KEYGUARD_ENABLED.equals(uri)) {
+ mBiometricEnabledOnKeyguard.put(userId, Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED,
+ DEFAULT_KEYGUARD_ENABLED ? 1 : 0 /* default */,
+ userId) != 0);
+
+ if (userId == ActivityManager.getCurrentUser() && !selfChange) {
+ notifyEnabledOnKeyguardCallbacks(userId);
+ }
+ } else if (BIOMETRIC_APP_ENABLED.equals(uri)) {
+ mBiometricEnabledForApps.put(userId, Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.BIOMETRIC_APP_ENABLED,
+ DEFAULT_APP_ENABLED ? 1 : 0 /* default */,
+ userId) != 0);
}
}
- public boolean getFaceEnabledOnKeyguard() {
- final int user = ActivityManager.getCurrentUser();
- if (!mFaceEnabledOnKeyguard.containsKey(user)) {
- onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, user);
+ public boolean getEnabledOnKeyguard(int userId) {
+ if (!mBiometricEnabledOnKeyguard.containsKey(userId)) {
+ if (mUseLegacyFaceOnlySettings) {
+ onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, userId);
+ } else {
+ onChange(true /* selfChange */, BIOMETRIC_KEYGUARD_ENABLED, userId);
+ }
}
- return mFaceEnabledOnKeyguard.get(user);
+ return mBiometricEnabledOnKeyguard.get(userId);
}
- public boolean getFaceEnabledForApps(int userId) {
- if (!mFaceEnabledForApps.containsKey(userId)) {
- onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId);
+ public boolean getEnabledForApps(int userId) {
+ if (!mBiometricEnabledForApps.containsKey(userId)) {
+ if (mUseLegacyFaceOnlySettings) {
+ onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId);
+ } else {
+ onChange(true /* selfChange */, BIOMETRIC_APP_ENABLED, userId);
+ }
}
- return mFaceEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED);
+ return mBiometricEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED);
}
public boolean getConfirmationAlwaysRequired(@BiometricAuthenticator.Modality int modality,
@@ -442,8 +501,8 @@
void notifyEnabledOnKeyguardCallbacks(int userId) {
List<EnabledOnKeyguardCallback> callbacks = mCallbacks;
for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).notify(BiometricSourceType.FACE,
- mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
+ callbacks.get(i).notify(
+ mBiometricEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
userId);
}
}
@@ -462,9 +521,9 @@
}
}
- void notify(BiometricSourceType sourceType, boolean enabled, int userId) {
+ void notify(boolean enabled, int userId) {
try {
- mCallback.onChanged(sourceType, enabled, userId);
+ mCallback.onChanged(enabled, userId);
} catch (DeadObjectException e) {
Slog.w(TAG, "Death while invoking notify", e);
mEnabledOnKeyguardCallbacks.remove(this);
@@ -747,8 +806,8 @@
mEnabledOnKeyguardCallbacks.add(new EnabledOnKeyguardCallback(callback));
try {
- callback.onChanged(BiometricSourceType.FACE,
- mSettingObserver.getFaceEnabledOnKeyguard(), callingUserId);
+ callback.onChanged(mSettingObserver.getEnabledOnKeyguard(callingUserId),
+ callingUserId);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
}
@@ -1347,6 +1406,9 @@
}
private void dumpInternal(PrintWriter pw) {
+ pw.println("Legacy Settings: " + mSettingObserver.mUseLegacyFaceOnlySettings);
+ pw.println();
+
pw.println("Sensors:");
for (BiometricSensor sensor : mSensors) {
pw.println(" " + sensor);
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 262cb36..c4bd18b 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -197,17 +197,7 @@
private static boolean isEnabledForApp(BiometricService.SettingObserver settingObserver,
@BiometricAuthenticator.Modality int modality, int userId) {
- switch (modality) {
- case TYPE_FINGERPRINT:
- return true;
- case TYPE_IRIS:
- return true;
- case TYPE_FACE:
- return settingObserver.getFaceEnabledForApps(userId);
- default:
- Slog.w(TAG, "Unsupported modality: " + modality);
- return false;
- }
+ return settingObserver.getEnabledForApps(userId);
}
private static boolean isBiometricDisabledByDevicePolicy(
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index d56fd12..b795b54 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -375,12 +375,12 @@
}
@Override
- public void onFeaturesRetrieved(byte[] features, int enrollmentId) {
+ public void onFeaturesRetrieved(byte[] features) {
}
@Override
- public void onFeatureSet(int enrollmentId, byte feature) {
+ public void onFeatureSet(byte feature) {
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
index c63af7e..f1bfd53 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
@@ -32,6 +32,7 @@
*/
public class TestHal extends IFace.Stub {
private static final String TAG = "face.aidl.TestHal";
+
@Override
public SensorProps[] getSensorProps() {
Slog.w(TAG, "getSensorProps");
@@ -102,16 +103,16 @@
}
@Override
- public void getFeatures(int enrollmentId) throws RemoteException {
+ public void getFeatures() throws RemoteException {
Slog.w(TAG, "getFeatures");
- cb.onFeaturesRetrieved(new byte[0], enrollmentId);
+ cb.onFeaturesRetrieved(new byte[0]);
}
@Override
- public void setFeature(HardwareAuthToken hat, int enrollmentId,
- byte feature, boolean enabled) throws RemoteException {
+ public void setFeature(HardwareAuthToken hat, byte feature, boolean enabled)
+ throws RemoteException {
Slog.w(TAG, "setFeature");
- cb.onFeatureSet(enrollmentId, feature);
+ cb.onFeatureSet(feature);
}
@Override
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 1bbcede..b2d35f4 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -15,9 +15,6 @@
*/
package com.android.server.camera;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.os.Build.VERSION_CODES.M;
import android.annotation.IntDef;
@@ -27,15 +24,12 @@
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.hardware.CameraSessionStats;
import android.hardware.CameraStreamStats;
import android.hardware.ICameraService;
@@ -43,7 +37,6 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.display.DisplayManager;
import android.media.AudioManager;
-import android.metrics.LogMaker;
import android.nfc.INfcAdapter;
import android.os.Binder;
import android.os.Handler;
@@ -60,17 +53,16 @@
import android.util.Log;
import android.util.Slog;
import android.view.Display;
+import android.view.IDisplayWindowListener;
import android.view.Surface;
+import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.framework.protobuf.nano.MessageNano;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.wm.WindowManagerInternal;
import java.lang.annotation.Retention;
@@ -223,6 +215,37 @@
}
}
+ private final class DisplayWindowListener extends IDisplayWindowListener.Stub {
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ ICameraService cs = getCameraServiceRawLocked();
+ if (cs == null) return;
+
+ try {
+ cs.notifyDisplayConfigurationChange();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not notify cameraserver, remote exception: " + e);
+ // Not much we can do if camera service is dead.
+ }
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayRemoved(int displayId) { }
+
+ @Override
+ public void onFixedRotationStarted(int displayId, int newRotation) { }
+
+ @Override
+ public void onFixedRotationFinished(int displayId) { }
+ }
+
+
+ private final DisplayWindowListener mDisplayWindowListener = new DisplayWindowListener();
+
private final TaskStateHandler mTaskStackListener = new TaskStateHandler();
private final class TaskInfo {
@@ -236,13 +259,12 @@
private final class TaskStateHandler extends TaskStackListener {
private final Object mMapLock = new Object();
- // maps the current top level task id to its corresponding package name
+ // maps the package name to its corresponding current top level task id
@GuardedBy("mMapLock")
private final ArrayMap<String, TaskInfo> mTaskInfoMap = new ArrayMap<>();
@Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
- throws RemoteException {
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
synchronized (mMapLock) {
TaskInfo info = new TaskInfo();
info.frontTaskId = taskInfo.taskId;
@@ -257,7 +279,7 @@
}
@Override
- public void onTaskRemoved(int taskId) throws RemoteException {
+ public void onTaskRemoved(int taskId) {
synchronized (mMapLock) {
for (Map.Entry<String, TaskInfo> entry : mTaskInfoMap.entrySet()){
if (entry.getValue().frontTaskId == taskId) {
@@ -319,7 +341,7 @@
/**
* Gets whether crop-rotate-scale is needed.
*/
- private boolean getNeedCropRotateScale(Context ctx, String packageName,
+ private boolean getNeedCropRotateScale(@NonNull Context ctx, @NonNull String packageName,
@Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing) {
if (taskInfo == null) {
return false;
@@ -334,7 +356,7 @@
// Only enable the crop-rotate-scale workaround if the app targets M or below and is not
// resizeable.
- if ((ctx != null) && !isMOrBelow(ctx, packageName) && taskInfo.isResizeable) {
+ if (!isMOrBelow(ctx, packageName) && taskInfo.isResizeable) {
Slog.v(TAG,
"The activity is N or above and claims to support resizeable-activity. "
+ "Crop-rotate-scale is disabled.");
@@ -372,12 +394,8 @@
taskInfo.isFixedOrientationLandscape);
// We need to do crop-rotate-scale when camera is landscape and activity is portrait or
// vice versa.
- if ((taskInfo.isFixedOrientationPortrait && landscapeCamera)
- || (taskInfo.isFixedOrientationLandscape && !landscapeCamera)) {
- return true;
- } else {
- return false;
- }
+ return (taskInfo.isFixedOrientationPortrait && landscapeCamera)
+ || (taskInfo.isFixedOrientationLandscape && !landscapeCamera);
}
@Override
@@ -389,14 +407,10 @@
return false;
}
- // A few remaining todos:
- // 1) Do the same check when working in WM compatible mode. The sequence needs
- // to be adjusted and use orientation events as triggers for all active camera
- // clients.
- // 2) Modify the sensor orientation in camera characteristics along with any 3A regions
- // in capture requests/results to account for thea physical rotation. The former
- // is somewhat tricky as it assumes that camera clients always check for the current
- // value by retrieving the camera characteristics from the camera device.
+ // TODO: Modify the sensor orientation in camera characteristics along with any 3A
+ // regions in capture requests/results to account for thea physical rotation. The
+ // former is somewhat tricky as it assumes that camera clients always check for the
+ // current value by retrieving the camera characteristics from the camera device.
return getNeedCropRotateScale(mContext, packageName,
mTaskStackListener.getFrontTaskInfo(packageName), sensorOrientation,
lensFacing);
@@ -522,18 +536,25 @@
publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy);
publishLocalService(CameraServiceProxy.class, this);
-
- try {
- ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register task stack listener!");
- }
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
CameraStatsJobService.schedule(mContext);
+
+ try {
+ ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register task stack listener!");
+ }
+
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
+ mDisplayWindowListener);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register display window listener!");
+ }
}
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 9c10814..47c7e39 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -45,6 +45,7 @@
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -67,6 +68,7 @@
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextClassifierEvent;
import android.view.textclassifier.TextLinks;
import android.widget.Toast;
@@ -211,9 +213,18 @@
/** Uids that have already triggered a toast notification for {@link #primaryClip} */
final SparseBooleanArray mNotifiedUids = new SparseBooleanArray();
+ /**
+ * Uids that have already triggered a notification to text classifier for
+ * {@link #primaryClip}.
+ */
+ final SparseBooleanArray mNotifiedTextClassifierUids = new SparseBooleanArray();
+
final HashSet<String> activePermissionOwners
= new HashSet<String>();
+ /** The text classifier session that is used to annotate the text in the primary clip. */
+ TextClassifier mTextClassifier;
+
PerUserClipboard(int userId) {
this.userId = userId;
}
@@ -371,6 +382,7 @@
addActiveOwnerLocked(intendingUid, pkg);
PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
showAccessNotificationLocked(pkg, intendingUid, intendingUserId, clipboard);
+ notifyTextClassifierLocked(clipboard, pkg, intendingUid);
return clipboard.primaryClip;
}
}
@@ -580,6 +592,7 @@
}
clipboard.primaryClip = clip;
clipboard.mNotifiedUids.clear();
+ clipboard.mNotifiedTextClassifierUids.clear();
if (clip != null) {
clipboard.primaryClipUid = uid;
clipboard.mPrimaryClipPackage = sourcePackage;
@@ -619,6 +632,11 @@
@GuardedBy("mLock")
private void startClassificationLocked(@NonNull ClipData clip, @UserIdInt int userId) {
+ if (clip.getItemCount() == 0) {
+ clip.getDescription().setClassificationStatus(
+ ClipDescription.CLASSIFICATION_NOT_PERFORMED);
+ return;
+ }
TextClassifier classifier;
final long ident = Binder.clearCallingIdentity();
try {
@@ -627,17 +645,11 @@
new TextClassificationContext.Builder(
getContext().getPackageName(),
TextClassifier.WIDGET_TYPE_CLIPBOARD
- ).build()
- );
+ ).build()
+ );
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- if (clip.getItemCount() == 0) {
- clip.getDescription().setClassificationStatus(
- ClipDescription.CLASSIFICATION_NOT_PERFORMED);
- return;
- }
CharSequence text = clip.getItemAt(0).getText();
if (TextUtils.isEmpty(text) || text.length() > mMaxClassificationLength
|| text.length() > classifier.getMaxGenerateLinksTextLength()) {
@@ -645,7 +657,7 @@
ClipDescription.CLASSIFICATION_NOT_PERFORMED);
return;
}
-
+ getClipboardLocked(userId).mTextClassifier = classifier;
mWorkerHandler.post(() -> doClassification(text, clip, classifier));
}
@@ -653,12 +665,7 @@
private void doClassification(
CharSequence text, ClipData clip, TextClassifier classifier) {
TextLinks.Request request = new TextLinks.Request.Builder(text).build();
- TextLinks links;
- try {
- links = classifier.generateLinks(request);
- } finally {
- classifier.destroy();
- }
+ TextLinks links = classifier.generateLinks(request);
// Find the highest confidence for each entity in the text.
ArrayMap<String, Float> confidences = new ArrayMap<>();
@@ -979,6 +986,48 @@
&& item.getIntent() == null;
}
+ /** Potentially notifies the text classifier that an app is accessing a text clip. */
+ @GuardedBy("mLock")
+ private void notifyTextClassifierLocked(
+ PerUserClipboard clipboard, String callingPackage, int callingUid) {
+ if (clipboard.primaryClip == null) {
+ return;
+ }
+ ClipData.Item item = clipboard.primaryClip.getItemAt(0);
+ if (item == null) {
+ return;
+ }
+ if (!isText(clipboard.primaryClip)) {
+ return;
+ }
+ TextClassifier textClassifier = clipboard.mTextClassifier;
+ // Don't notify text classifier if we haven't used it to annotate the text in the clip.
+ if (textClassifier == null) {
+ return;
+ }
+ // Don't notify text classifier if the app reading the clipboard does not have the focus.
+ if (!mWm.isUidFocused(callingUid)) {
+ return;
+ }
+ // Don't notify text classifier again if already notified for this uid and clip.
+ if (clipboard.mNotifiedTextClassifierUids.get(callingUid)) {
+ return;
+ }
+ clipboard.mNotifiedTextClassifierUids.put(callingUid, true);
+ Binder.withCleanCallingIdentity(() -> {
+ TextClassifierEvent.TextLinkifyEvent pasteEvent =
+ new TextClassifierEvent.TextLinkifyEvent.Builder(
+ TextClassifierEvent.TYPE_READ_CLIPBOARD)
+ .setEventContext(new TextClassificationContext.Builder(
+ callingPackage, TextClassifier.WIDGET_TYPE_CLIPBOARD)
+ .build())
+ .setExtras(
+ Bundle.forPair("source_package", clipboard.mPrimaryClipPackage))
+ .build();
+ textClassifier.onTextClassifierEvent(pasteEvent);
+ });
+ }
+
private TextClassificationManager createTextClassificationManagerAsUser(@UserIdInt int userId) {
Context context = getContext().createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
return context.getSystemService(TextClassificationManager.class);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 4d310cb..584174e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -59,6 +59,7 @@
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
@@ -281,6 +282,9 @@
*/
public static final int ARG_AGENT_SUCCESS = 1;
+ // How long this network should linger for.
+ private int mLingerDurationMs;
+
// All inactivity timers for this network, sorted by expiry time. A timer is added whenever
// a request is moved to a network with a better score, regardless of whether the network is or
// was lingering or not. An inactivity timer is also added when a network connects
@@ -349,7 +353,8 @@
@NonNull NetworkScore score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
- QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps) {
+ int lingerDurationMs, QosCallbackTracker qosCallbackTracker,
+ ConnectivityService.Dependencies deps) {
Objects.requireNonNull(net);
Objects.requireNonNull(info);
Objects.requireNonNull(lp);
@@ -370,6 +375,7 @@
mHandler = handler;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
+ mLingerDurationMs = lingerDurationMs;
mQosCallbackTracker = qosCallbackTracker;
}
@@ -685,6 +691,12 @@
mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
}
+
+ @Override
+ public void sendLingerDuration(final int durationMs) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_LINGER_DURATION_CHANGED,
+ new Pair<>(NetworkAgentInfo.this, durationMs)).sendToTarget();
+ }
}
/**
@@ -954,13 +966,14 @@
/**
* Sets the specified requestId to linger on this network for the specified time. Called by
- * ConnectivityService when the request is moved to another network with a higher score, or
+ * ConnectivityService when any request is moved to another network with a higher score, or
* when a network is newly created.
*
* @param requestId The requestId of the request that no longer need to be served by this
* network. Or {@link NetworkRequest.REQUEST_ID_NONE} if this is the
- * {@code LingerTimer} for a newly created network.
+ * {@code InactivityTimer} for a newly created network.
*/
+ // TODO: Consider creating a dedicated function for nascent network, e.g. start/stopNascent.
public void lingerRequest(int requestId, long now, long duration) {
if (mInactivityTimerForRequest.get(requestId) != null) {
// Cannot happen. Once a request is lingering on a particular network, we cannot
@@ -976,6 +989,19 @@
}
/**
+ * Sets the specified requestId to linger on this network for the timeout set when
+ * initializing or modified by {@link #setLingerDuration(int)}. Called by
+ * ConnectivityService when any request is moved to another network with a higher score.
+ *
+ * @param requestId The requestId of the request that no longer need to be served by this
+ * network.
+ * @param now current system timestamp obtained by {@code SystemClock.elapsedRealtime}.
+ */
+ public void lingerRequest(int requestId, long now) {
+ lingerRequest(requestId, now, mLingerDurationMs);
+ }
+
+ /**
* Cancel lingering. Called by ConnectivityService when a request is added to this network.
* Returns true if the given requestId was lingering on this network, false otherwise.
*/
@@ -1012,6 +1038,7 @@
}
if (newExpiry > 0) {
+ // If the newExpiry timestamp is in the past, the wakeup message will fire immediately.
mInactivityMessage = new WakeupMessage(
mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
@@ -1041,8 +1068,33 @@
}
/**
- * Return whether the network is just connected and about to be torn down because of not
- * satisfying any request.
+ * Set the linger duration for this NAI.
+ * @param durationMs The new linger duration, in milliseconds.
+ */
+ public void setLingerDuration(final int durationMs) {
+ final long diff = durationMs - mLingerDurationMs;
+ final ArrayList<InactivityTimer> newTimers = new ArrayList<>();
+ for (final InactivityTimer timer : mInactivityTimers) {
+ if (timer.requestId == NetworkRequest.REQUEST_ID_NONE) {
+ // Don't touch nascent timer, re-add as is.
+ newTimers.add(timer);
+ } else {
+ newTimers.add(new InactivityTimer(timer.requestId, timer.expiryMs + diff));
+ }
+ }
+ mInactivityTimers.clear();
+ mInactivityTimers.addAll(newTimers);
+ updateInactivityTimer();
+ mLingerDurationMs = durationMs;
+ }
+
+ /**
+ * Return whether the network satisfies no request, but is still being kept up
+ * because it has just connected less than
+ * {@code ConnectivityService#DEFAULT_NASCENT_DELAY_MS}ms ago and is thus still considered
+ * nascent. Note that nascent mechanism uses inactivity timer which isn't
+ * associated with a request. Thus, use {@link NetworkRequest#REQUEST_ID_NONE} to identify it.
+ *
*/
public boolean isNascent() {
return mInactive && mInactivityTimers.size() == 1
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java
index c123ea7..2b345e5 100644
--- a/services/core/java/com/android/server/connectivity/NetworkRanker.java
+++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java
@@ -24,6 +24,7 @@
import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY;
import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI;
+import static com.android.net.module.util.CollectionUtils.filter;
import static com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED;
import static com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED;
import static com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD;
@@ -66,18 +67,6 @@
public NetworkRanker() { }
- // TODO : move to module utils CollectionUtils.
- @NonNull private static <T> ArrayList<T> filter(@NonNull final Collection<T> source,
- @NonNull final Predicate<T> test) {
- final ArrayList<T> matches = new ArrayList<>();
- for (final T e : source) {
- if (test.test(e)) {
- matches.add(e);
- }
- }
- return matches;
- }
-
/**
* Find the best network satisfying this request among the list of passed networks.
*/
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index e3eeb6c4..3a7220f7 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -394,7 +394,8 @@
private void startDreamLocked(final ComponentName name,
final boolean isTest, final boolean canDoze, final int userId) {
- if (Objects.equals(mCurrentDreamName, name)
+ if (!mCurrentDreamIsWaking
+ && Objects.equals(mCurrentDreamName, name)
&& mCurrentDreamIsTest == isTest
&& mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 031c057..754fa25 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1253,6 +1253,7 @@
void setAudioStatus(boolean mute, int volume) {
if (!isTvDeviceEnabled()
|| !tv().isSystemAudioActivated()
+ || !tv().isArcEstablished() // Don't update TV volume when SAM is on and ARC is off
|| getHdmiCecVolumeControl()
== HdmiControlManager.VOLUME_CONTROL_DISABLED) {
return;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ed8ea18..7994fcc 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4100,13 +4100,10 @@
}
@Override
- public void removeImeSurfaceFromWindow(IBinder windowToken,
- IVoidResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback, () -> {
- // No permission check, because we'll only execute the request if the calling window is
- // also the current IME client.
- mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
- });
+ public void removeImeSurfaceFromWindowAsync(IBinder windowToken) {
+ // No permission check, because we'll only execute the request if the calling window is
+ // also the current IME client.
+ mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index ef1489b..6244743 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1510,10 +1510,8 @@
@BinderThread
@Override
- public void removeImeSurfaceFromWindow(IBinder windowToken,
- IVoidResultCallback resultCallback) {
+ public void removeImeSurfaceFromWindowAsync(IBinder windowToken) {
reportNotSupported();
- CallbackUtils.onResult(resultCallback, () -> { });
}
@BinderThread
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 6b28fbc..59f00a2 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1773,7 +1773,7 @@
} else {
final byte[] hashFactor = getHashFactor(password, userHandle);
final byte[] salt = getSalt(userHandle).getBytes();
- String hash = password.passwordToHistoryHash(hashFactor, salt);
+ String hash = password.passwordToHistoryHash(salt, hashFactor);
if (hash == null) {
Slog.e(TAG, "Compute new style password hash failed, fallback to legacy style");
hash = password.legacyPasswordToHash(salt);
@@ -3658,7 +3658,7 @@
}
@Override
- public boolean armRebootEscrow() {
+ public @ArmRebootEscrowErrorCode int armRebootEscrow() {
return mRebootEscrowManager.armRebootEscrowIfNeeded();
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 76ecc1a..c01523a 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -18,6 +18,15 @@
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+import static com.android.internal.widget.LockSettingsInternal.ArmRebootEscrowErrorCode;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -577,16 +586,14 @@
mRebootEscrowWanted = false;
setRebootEscrowReady(false);
-
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) {
- Slog.w(TAG,
- "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
- return;
+ Slog.w(TAG, "RebootEscrowProvider is unavailable for clear request");
+ } else {
+ rebootEscrowProvider.clearRebootEscrowKey();
}
clearMetricsStorage();
- rebootEscrowProvider.clearRebootEscrowKey();
List<UserInfo> users = mUserManager.getUsers();
for (UserInfo user : users) {
@@ -596,20 +603,30 @@
mEventLog.addEntry(RebootEscrowEvent.CLEARED_LSKF_REQUEST);
}
- boolean armRebootEscrowIfNeeded() {
+ @ArmRebootEscrowErrorCode int armRebootEscrowIfNeeded() {
if (!mRebootEscrowReady) {
- return false;
+ return ARM_REBOOT_ERROR_ESCROW_NOT_READY;
}
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) {
Slog.w(TAG,
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
- return false;
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_NO_PROVIDER;
}
+ int expectedProviderType = mInjector.serverBasedResumeOnReboot()
+ ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
+ : RebootEscrowProviderInterface.TYPE_HAL;
int actualProviderType = rebootEscrowProvider.getType();
- // TODO(b/183140900) Fail the reboot if provider type mismatches.
+ if (expectedProviderType != actualProviderType) {
+ Slog.w(TAG, "Expect reboot escrow provider " + expectedProviderType
+ + ", but the RoR is prepared with " + actualProviderType
+ + ". Please prepare the RoR again.");
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+ }
RebootEscrowKey escrowKey;
synchronized (mKeyGenerationLock) {
@@ -618,30 +635,38 @@
if (escrowKey == null) {
Slog.e(TAG, "Escrow key is null, but escrow was marked as ready");
- return false;
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_NO_ESCROW_KEY;
}
// We will use the same key from keystore to encrypt the escrow key and escrow data blob.
SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
if (kk == null) {
Slog.e(TAG, "Failed to get encryption key from keystore.");
- return false;
- }
- boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
- if (armedRebootEscrow) {
- mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
- mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
- USER_SYSTEM);
- // Store the vbmeta digest of both slots.
- mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
- USER_SYSTEM);
- mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
- mInjector.getVbmetaDigest(true), USER_SYSTEM);
- mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
- mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
+ clearRebootEscrowIfNeeded();
+ return ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
}
- return armedRebootEscrow;
+ // TODO(b/183140900) design detailed errors for store escrow key errors.
+ // We don't clear rebootEscrow here, because some errors may be recoverable, e.g. network
+ // unavailable for server based provider.
+ boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
+ if (!armedRebootEscrow) {
+ return ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+ }
+
+ mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
+ mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
+ USER_SYSTEM);
+ // Store the vbmeta digest of both slots.
+ mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
+ USER_SYSTEM);
+ mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
+ mInjector.getVbmetaDigest(true), USER_SYSTEM);
+ mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
+ mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
+
+ return ARM_REBOOT_ERROR_NONE;
}
private void setRebootEscrowReady(boolean ready) {
@@ -663,10 +688,6 @@
}
boolean clearRebootEscrow() {
- if (mInjector.getRebootEscrowProvider() == null) {
- return false;
- }
-
clearRebootEscrowIfNeeded();
return true;
}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 8bd3b1e..42b7c9d3 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -100,7 +100,7 @@
IntentFilter deletionFilter = new IntentFilter(ACTION_HISTORY_DELETION);
deletionFilter.addDataScheme(SCHEME_DELETION);
- mContext.registerReceiver(mFileCleaupReceiver, deletionFilter);
+ mContext.registerReceiver(mFileCleanupReceiver, deletionFilter);
}
public void init() {
@@ -273,13 +273,36 @@
}
}
+ /**
+ * Remove the first entry from the list of history files whose file matches the given file path.
+ *
+ * This method is necessary for anything that only has an absolute file path rather than an
+ * AtomicFile object from the list of history files.
+ *
+ * filePath should be an absolute path.
+ */
+ void removeFilePathFromHistory(String filePath) {
+ if (filePath == null) {
+ return;
+ }
+
+ Iterator<AtomicFile> historyFileItr = mHistoryFiles.iterator();
+ while (historyFileItr.hasNext()) {
+ final AtomicFile af = historyFileItr.next();
+ if (af != null && filePath.equals(af.getBaseFile().getAbsolutePath())) {
+ historyFileItr.remove();
+ return;
+ }
+ }
+ }
+
private void deleteFile(AtomicFile file) {
if (DEBUG) {
Slog.d(TAG, "Removed " + file.getBaseFile().getName());
}
file.delete();
// TODO: delete all relevant bitmaps, once they exist
- mHistoryFiles.remove(file);
+ removeFilePathFromHistory(file.getBaseFile().getAbsolutePath());
}
private void scheduleDeletion(File file, long creationTime, int retentionDays) {
@@ -342,7 +365,7 @@
}
}
- private final BroadcastReceiver mFileCleaupReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mFileCleanupReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -358,7 +381,7 @@
Slog.d(TAG, "Removed " + fileToDelete.getBaseFile().getName());
}
fileToDelete.delete();
- mHistoryFiles.remove(fileToDelete);
+ removeFilePathFromHistory(filePath);
}
} catch (Exception e) {
Slog.e(TAG, "Failed to delete notification history file", e);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3ddfe6c..1e6e5cb 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -380,8 +380,6 @@
static final int INVALID_UID = -1;
static final String ROOT_PKG = "root";
- static final boolean ENABLE_BLOCKED_TOASTS = true;
-
static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
Adjustment.KEY_CONTEXTUAL_ACTIONS,
Adjustment.KEY_TEXT_REPLIES,
@@ -3165,34 +3163,11 @@
}
final int callingUid = Binder.getCallingUid();
- final UserHandle callingUser = Binder.getCallingUserHandle();
+ checkCallerIsSameApp(pkg);
final boolean isSystemToast = isCallerSystemOrPhone()
|| PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
- final boolean isPackageSuspended = isPackagePaused(pkg);
- final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
- callingUid);
-
- final boolean appIsForeground;
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- appIsForeground = mActivityManager.getUidImportance(callingUid)
- == IMPORTANCE_FOREGROUND;
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
-
- if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage
- && !appIsForeground) || isPackageSuspended)) {
- Slog.e(TAG, "Suppressing toast from package " + pkg
- + (isPackageSuspended ? " due to package suspended."
- : " by user request."));
- return;
- }
-
boolean isAppRenderedToast = (callback != null);
- if (blockToast(callingUid, isSystemToast, isAppRenderedToast)) {
- Slog.w(TAG, "Blocking custom toast from package " + pkg
- + " due to package not in the foreground at time the toast was posted");
+ if (!checkCanEnqueueToast(pkg, callingUid, isAppRenderedToast, isSystemToast)) {
return;
}
@@ -3246,6 +3221,39 @@
}
}
+ private boolean checkCanEnqueueToast(String pkg, int callingUid,
+ boolean isAppRenderedToast, boolean isSystemToast) {
+ final boolean isPackageSuspended = isPackagePaused(pkg);
+ final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
+ callingUid);
+
+ final boolean appIsForeground;
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ appIsForeground = mActivityManager.getUidImportance(callingUid)
+ == IMPORTANCE_FOREGROUND;
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+
+ if (!isSystemToast && ((notificationsDisabledForPackage && !appIsForeground)
+ || isPackageSuspended)) {
+ Slog.e(TAG, "Suppressing toast from package " + pkg
+ + (isPackageSuspended ? " due to package suspended."
+ : " by user request."));
+ return false;
+ }
+
+ if (blockToast(callingUid, isSystemToast, isAppRenderedToast,
+ isPackageInForegroundForToast(callingUid))) {
+ Slog.w(TAG, "Blocking custom toast from package " + pkg
+ + " due to package not in the foreground at time the toast was posted");
+ return false;
+ }
+
+ return true;
+ }
+
@Override
public void cancelToast(String pkg, IBinder token) {
Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token);
@@ -7692,12 +7700,13 @@
boolean isWithinQuota =
mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG)
|| isExemptFromRateLimiting(record.pkg, userId);
+ boolean isPackageInForeground = isPackageInForegroundForToast(record.uid);
if (tryShowToast(
- record, rateLimitingEnabled, isWithinQuota)) {
+ record, rateLimitingEnabled, isWithinQuota, isPackageInForeground)) {
scheduleDurationReachedLocked(record, lastToastWasTextRecord);
mIsCurrentToastShown = true;
- if (rateLimitingEnabled) {
+ if (rateLimitingEnabled && !isPackageInForeground) {
mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG);
}
return;
@@ -7713,14 +7722,15 @@
/** Returns true if it successfully showed the toast. */
private boolean tryShowToast(ToastRecord record, boolean rateLimitingEnabled,
- boolean isWithinQuota) {
- if (rateLimitingEnabled && !isWithinQuota) {
+ boolean isWithinQuota, boolean isPackageInForeground) {
+ if (rateLimitingEnabled && !isWithinQuota && !isPackageInForeground) {
reportCompatRateLimitingToastsChange(record.uid);
Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the "
+ "following toast was blocked and discarded: " + record);
return false;
}
- if (blockToast(record.uid, record.isSystemToast, record.isAppRendered())) {
+ if (blockToast(record.uid, record.isSystemToast, record.isAppRendered(),
+ isPackageInForeground)) {
Slog.w(TAG, "Blocking custom toast from package " + record.pkg
+ " due to package not in the foreground at the time of showing the toast");
return false;
@@ -7911,10 +7921,11 @@
* with targetSdk < R. For apps with targetSdk R+, text toasts are not app-rendered, so
* isAppRenderedToast == true means it's a custom toast.
*/
- private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast) {
+ private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast,
+ boolean isPackageInForeground) {
return isAppRenderedToast
&& !isSystemToast
- && !isPackageInForegroundForToast(uid)
+ && !isPackageInForeground
&& CompatChanges.isChangeEnabled(CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, uid);
}
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
index a9dbb2f..94a1f3b 100644
--- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
@@ -28,10 +30,10 @@
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@@ -84,14 +86,15 @@
* See class comment for specific types.
*/
@GuardedBy("mLock")
- private final Map<String, Map<String, Set<String>>> mActorToTargetToOverlays = new HashMap<>();
+ private final ArrayMap<String, ArrayMap<String, ArraySet<String>>> mActorToTargetToOverlays =
+ new ArrayMap<>();
/**
* Keys are actor package names, values are generic package names the actor should be able
* to see.
*/
@GuardedBy("mLock")
- private final Map<String, Set<String>> mActorPkgToPkgs = new HashMap<>();
+ private final ArrayMap<String, Set<String>> mActorPkgToPkgs = new ArrayMap<>();
@GuardedBy("mLock")
private boolean mDeferRebuild;
@@ -160,21 +163,26 @@
*
* @param pkg the package to add
* @param otherPkgs map of other packages to consider, excluding {@param pkg}
+ * @return Set of packages that may have changed visibility
*/
- public void addPkg(AndroidPackage pkg, Map<String, AndroidPackage> otherPkgs) {
+ public ArraySet<String> addPkg(AndroidPackage pkg, Map<String, AndroidPackage> otherPkgs) {
synchronized (mLock) {
+ ArraySet<String> changed = new ArraySet<>();
+
if (!pkg.getOverlayables().isEmpty()) {
- addTarget(pkg, otherPkgs);
+ addTarget(pkg, otherPkgs, changed);
}
// TODO(b/135203078): Replace with isOverlay boolean flag check; fix test mocks
if (!mProvider.getTargetToOverlayables(pkg).isEmpty()) {
- addOverlay(pkg, otherPkgs);
+ addOverlay(pkg, otherPkgs, changed);
}
if (!mDeferRebuild) {
rebuild();
}
+
+ return changed;
}
}
@@ -184,27 +192,40 @@
* of {@link SystemConfig#getNamedActors()}.
*
* @param pkgName name to remove, as was added through {@link #addPkg(AndroidPackage, Map)}
+ * @return Set of packages that may have changed visibility
*/
- public void removePkg(String pkgName) {
+ public ArraySet<String> removePkg(String pkgName) {
synchronized (mLock) {
- removeTarget(pkgName);
- removeOverlay(pkgName);
+ ArraySet<String> changedPackages = new ArraySet<>();
+ removeTarget(pkgName, changedPackages);
+ removeOverlay(pkgName, changedPackages);
if (!mDeferRebuild) {
rebuild();
}
+
+ return changedPackages;
}
}
- private void removeTarget(String target) {
+ /**
+ * @param changedPackages Ongoing collection of packages that may have changed visibility
+ */
+ private void removeTarget(String target, @NonNull Collection<String> changedPackages) {
synchronized (mLock) {
- Iterator<Map<String, Set<String>>> iterator =
- mActorToTargetToOverlays.values().iterator();
- while (iterator.hasNext()) {
- Map<String, Set<String>> next = iterator.next();
- next.remove(target);
- if (next.isEmpty()) {
- iterator.remove();
+ int size = mActorToTargetToOverlays.size();
+ for (int index = size - 1; index >= 0; index--) {
+ ArrayMap<String, ArraySet<String>> targetToOverlays =
+ mActorToTargetToOverlays.valueAt(index);
+ if (targetToOverlays.containsKey(target)) {
+ targetToOverlays.remove(target);
+
+ String actor = mActorToTargetToOverlays.keyAt(index);
+ changedPackages.add(mProvider.getActorPkg(actor));
+
+ if (targetToOverlays.isEmpty()) {
+ mActorToTargetToOverlays.removeAt(index);
+ }
}
}
}
@@ -215,16 +236,19 @@
*
* If a target overlays itself, it will not be associated with itself, as only one half of the
* relationship needs to exist for visibility purposes.
+ *
+ * @param changedPackages Ongoing collection of packages that may have changed visibility
*/
- private void addTarget(AndroidPackage targetPkg, Map<String, AndroidPackage> otherPkgs) {
+ private void addTarget(AndroidPackage targetPkg, Map<String, AndroidPackage> otherPkgs,
+ @NonNull Collection<String> changedPackages) {
synchronized (mLock) {
String target = targetPkg.getPackageName();
- removeTarget(target);
+ removeTarget(target, changedPackages);
Map<String, String> overlayablesToActors = targetPkg.getOverlayables();
for (String overlayable : overlayablesToActors.keySet()) {
String actor = overlayablesToActors.get(overlayable);
- addTargetToMap(actor, target);
+ addTargetToMap(actor, target, changedPackages);
for (AndroidPackage overlayPkg : otherPkgs.values()) {
Map<String, Set<String>> targetToOverlayables =
@@ -235,18 +259,38 @@
}
if (overlayables.contains(overlayable)) {
- addOverlayToMap(actor, target, overlayPkg.getPackageName());
+ String overlay = overlayPkg.getPackageName();
+ addOverlayToMap(actor, target, overlay, changedPackages);
}
}
}
}
}
- private void removeOverlay(String overlay) {
+ /**
+ * @param changedPackages Ongoing collection of packages that may have changed visibility
+ */
+ private void removeOverlay(String overlay, @NonNull Collection<String> changedPackages) {
synchronized (mLock) {
- for (Map<String, Set<String>> targetToOverlays : mActorToTargetToOverlays.values()) {
- for (Set<String> overlays : targetToOverlays.values()) {
- overlays.remove(overlay);
+ int actorsSize = mActorToTargetToOverlays.size();
+ for (int actorIndex = actorsSize - 1; actorIndex >= 0; actorIndex--) {
+ ArrayMap<String, ArraySet<String>> targetToOverlays =
+ mActorToTargetToOverlays.valueAt(actorIndex);
+ int targetsSize = targetToOverlays.size();
+ for (int targetIndex = targetsSize - 1; targetIndex >= 0; targetIndex--) {
+ final Set<String> overlays = targetToOverlays.valueAt(targetIndex);
+
+ if (overlays.remove(overlay)) {
+ String actor = mActorToTargetToOverlays.keyAt(actorIndex);
+ changedPackages.add(mProvider.getActorPkg(actor));
+
+ // targetToOverlays should not be removed here even if empty as the actor
+ // will still have visibility to the target even if no overlays exist
+ }
+ }
+
+ if (targetToOverlays.isEmpty()) {
+ mActorToTargetToOverlays.removeAt(actorIndex);
}
}
}
@@ -257,11 +301,14 @@
*
* If an overlay targets itself, it will not be associated with itself, as only one half of the
* relationship needs to exist for visibility purposes.
+ *
+ * @param changedPackages Ongoing collection of packages that may have changed visibility
*/
- private void addOverlay(AndroidPackage overlayPkg, Map<String, AndroidPackage> otherPkgs) {
+ private void addOverlay(AndroidPackage overlayPkg, Map<String, AndroidPackage> otherPkgs,
+ @NonNull Collection<String> changedPackages) {
synchronized (mLock) {
String overlay = overlayPkg.getPackageName();
- removeOverlay(overlay);
+ removeOverlay(overlay, changedPackages);
Map<String, Set<String>> targetToOverlayables =
mProvider.getTargetToOverlayables(overlayPkg);
@@ -280,7 +327,7 @@
if (TextUtils.isEmpty(actor)) {
continue;
}
- addOverlayToMap(actor, targetPkgName, overlay);
+ addOverlayToMap(actor, targetPkgName, overlay, changedPackages);
}
}
}
@@ -312,7 +359,8 @@
continue;
}
- Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+ ArrayMap<String, ArraySet<String>> targetToOverlays =
+ mActorToTargetToOverlays.get(actor);
Set<String> pkgs = new HashSet<>();
for (String target : targetToOverlays.keySet()) {
@@ -326,36 +374,51 @@
}
}
- private void addTargetToMap(String actor, String target) {
- Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+ /**
+ * @param changedPackages Ongoing collection of packages that may have changed visibility
+ */
+ private void addTargetToMap(String actor, String target,
+ @NonNull Collection<String> changedPackages) {
+ ArrayMap<String, ArraySet<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
if (targetToOverlays == null) {
- targetToOverlays = new HashMap<>();
+ targetToOverlays = new ArrayMap<>();
mActorToTargetToOverlays.put(actor, targetToOverlays);
}
- Set<String> overlays = targetToOverlays.get(target);
+ ArraySet<String> overlays = targetToOverlays.get(target);
if (overlays == null) {
- overlays = new HashSet<>();
+ overlays = new ArraySet<>();
targetToOverlays.put(target, overlays);
}
+
+ // For now, only actors themselves can gain or lose visibility through package changes
+ changedPackages.add(mProvider.getActorPkg(actor));
}
- private void addOverlayToMap(String actor, String target, String overlay) {
+ /**
+ * @param changedPackages Ongoing collection of packages that may have changed visibility
+ */
+ private void addOverlayToMap(String actor, String target, String overlay,
+ @NonNull Collection<String> changedPackages) {
synchronized (mLock) {
- Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+ ArrayMap<String, ArraySet<String>> targetToOverlays =
+ mActorToTargetToOverlays.get(actor);
if (targetToOverlays == null) {
- targetToOverlays = new HashMap<>();
+ targetToOverlays = new ArrayMap<>();
mActorToTargetToOverlays.put(actor, targetToOverlays);
}
- Set<String> overlays = targetToOverlays.get(target);
+ ArraySet<String> overlays = targetToOverlays.get(target);
if (overlays == null) {
- overlays = new HashSet<>();
+ overlays = new ArraySet<>();
targetToOverlays.put(target, overlays);
}
overlays.add(overlay);
}
+
+ // For now, only actors themselves can gain or lose visibility through package changes
+ changedPackages.add(mProvider.getActorPkg(actor));
}
public interface Provider {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index ca8202f..4f527f2 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -662,11 +662,27 @@
removePackage(newPkgSetting);
}
mStateProvider.runWithState((settings, users) -> {
- addPackageInternal(newPkgSetting, settings);
+ ArraySet<String> additionalChangedPackages =
+ addPackageInternal(newPkgSetting, settings);
synchronized (mCacheLock) {
if (mShouldFilterCache != null) {
updateShouldFilterCacheForPackage(mShouldFilterCache, null, newPkgSetting,
settings, users, settings.size());
+ if (additionalChangedPackages != null) {
+ for (int index = 0; index < additionalChangedPackages.size(); index++) {
+ String changedPackage = additionalChangedPackages.valueAt(index);
+ PackageSetting changedPkgSetting = settings.get(changedPackage);
+ if (changedPkgSetting == null) {
+ // It's possible for the overlay mapper to know that an actor
+ // package changed via an explicit reference, even if the actor
+ // isn't installed, so skip if that's the case.
+ continue;
+ }
+
+ updateShouldFilterCacheForPackage(mShouldFilterCache, null,
+ changedPkgSetting, settings, users, settings.size());
+ }
+ }
} // else, rebuild entire cache when system is ready
}
});
@@ -676,7 +692,12 @@
}
}
- private void addPackageInternal(PackageSetting newPkgSetting,
+ /**
+ * @return Additional packages that may have had their viewing visibility changed and may need
+ * to be updated in the cache. Returns null if there are no additional packages.
+ */
+ @Nullable
+ private ArraySet<String> addPackageInternal(PackageSetting newPkgSetting,
ArrayMap<String, PackageSetting> existingSettings) {
if (Objects.equals("android", newPkgSetting.name)) {
// let's set aside the framework signatures
@@ -692,8 +713,7 @@
final AndroidPackage newPkg = newPkgSetting.pkg;
if (newPkg == null) {
- // nothing to add
- return;
+ return null;
}
if (mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts())) {
@@ -765,8 +785,13 @@
existingPkgs.put(pkgSetting.name, pkgSetting.pkg);
}
}
- mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
+
+ ArraySet<String> changedPackages =
+ mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
+
mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
+
+ return changedPackages;
}
@GuardedBy("mCacheLock")
@@ -1080,7 +1105,9 @@
}
}
- mOverlayReferenceMapper.removePkg(setting.name);
+ ArraySet<String> additionalChangedPackages =
+ mOverlayReferenceMapper.removePkg(setting.name);
+
mFeatureConfig.updatePackageState(setting, true /*removed*/);
// After removing all traces of the package, if it's part of a shared user, re-add other
@@ -1109,6 +1136,25 @@
siblingSetting, settings, users, settings.size());
}
}
+
+ if (mShouldFilterCache != null) {
+ if (additionalChangedPackages != null) {
+ for (int index = 0; index < additionalChangedPackages.size(); index++) {
+ String changedPackage = additionalChangedPackages.valueAt(index);
+ PackageSetting changedPkgSetting = settings.get(changedPackage);
+ if (changedPkgSetting == null) {
+ // It's possible for the overlay mapper to know that an actor
+ // package changed via an explicit reference, even if the actor
+ // isn't installed, so skip if that's the case.
+ continue;
+ }
+
+ updateShouldFilterCacheForPackage(mShouldFilterCache, null,
+ changedPkgSetting, settings, users, settings.size());
+ }
+ }
+ }
+
onChanged();
}
});
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
index 6875b8a..ec79483 100644
--- a/services/core/java/com/android/server/pm/DumpState.java
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -45,6 +45,7 @@
public static final int DUMP_QUERIES = 1 << 26;
public static final int DUMP_KNOWN_PACKAGES = 1 << 27;
public static final int DUMP_PER_UID_READ_TIMEOUTS = 1 << 28;
+ public static final int DUMP_SNAPSHOT_STATISTICS = 1 << 29;
public static final int OPTION_SHOW_FILTERS = 1 << 0;
public static final int OPTION_DUMP_ALL_COMPONENTS = 1 << 1;
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 7bf7042..bf323e7 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -57,6 +57,7 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.utils.Snappable;
+import com.android.server.utils.SnapshotCache;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
import com.android.server.utils.Watched;
@@ -146,7 +147,7 @@
/**
* The cached snapshot
*/
- private volatile InstantAppRegistry mSnapshot = null;
+ private final SnapshotCache<InstantAppRegistry> mSnapshot;
/**
* Watchable machinery
@@ -162,7 +163,6 @@
return mWatchable.isRegisteredObserver(observer);
}
public void dispatchChange(@Nullable Watchable what) {
- mSnapshot = null;
mWatchable.dispatchChange(what);
}
/**
@@ -180,6 +180,16 @@
}
};
+ private SnapshotCache<InstantAppRegistry> makeCache() {
+ return new SnapshotCache<InstantAppRegistry>(this, this) {
+ @Override
+ public InstantAppRegistry createSnapshot() {
+ InstantAppRegistry s = new InstantAppRegistry(mSource);
+ s.mWatchable.seal();
+ return s;
+ }};
+ }
+
public InstantAppRegistry(PackageManagerService service,
PermissionManagerServiceInternal permissionManager) {
mService = service;
@@ -194,6 +204,8 @@
mInstantGrants.registerObserver(mObserver);
mInstalledInstantAppUids.registerObserver(mObserver);
Watchable.verifyWatchedAttributes(this, mObserver);
+
+ mSnapshot = makeCache();
}
/**
@@ -211,20 +223,15 @@
mInstalledInstantAppUids = new WatchedSparseArray<WatchedSparseBooleanArray>(
r.mInstalledInstantAppUids);
- // Do not register any observers. This is a clone
+ // Do not register any observers. This is a snapshot.
+ mSnapshot = null;
}
/**
* Return a snapshot: the value is the cached snapshot if available.
*/
public InstantAppRegistry snapshot() {
- InstantAppRegistry s = mSnapshot;
- if (s == null) {
- s = new InstantAppRegistry(this);
- s.mWatchable.seal();
- mSnapshot = s;
- }
- return s;
+ return mSnapshot.snapshot();
}
@GuardedBy("mService.mLock")
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 91a66ac..dd80e16 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -636,9 +636,25 @@
Objects.requireNonNull(component);
// All right, create the sender.
- Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
+ final int callingUid = injectBinderCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
+ final PackageManagerInternal pmInt =
+ LocalServices.getService(PackageManagerInternal.class);
+ Intent packageIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT)
+ .setPackage(component.getPackageName());
+ List<ResolveInfo> apps = pmInt.queryIntentActivities(packageIntent,
+ packageIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ callingUid, user.getIdentifier());
+ // ensure that the component is present in the list
+ if (!apps.stream().anyMatch(
+ ri -> component.getClassName().equals(ri.activityInfo.name))) {
+ return null;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
final PendingIntent pi = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2849982..59039ba 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1914,6 +1914,18 @@
*/
private interface Computer {
+ /**
+ * Administrative statistics: record that the snapshot has been used. Every call
+ * to use() increments the usage counter.
+ */
+ void use();
+
+ /**
+ * Fetch the snapshot usage counter.
+ * @return The number of times this snapshot was used.
+ */
+ int getUsed();
+
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid,
int userId, boolean resolveForStart, boolean allowDynamicSplits);
@@ -2065,6 +2077,9 @@
*/
private static class ComputerEngine implements Computer {
+ // The administrative use counter.
+ private int mUsed = 0;
+
// Cached attributes. The names in this class are the same as the
// names in PackageManagerService; see that class for documentation.
protected final Settings mSettings;
@@ -2157,6 +2172,20 @@
mService = args.service;
}
+ /**
+ * Record that the snapshot was used.
+ */
+ public void use() {
+ mUsed++;
+ }
+
+ /**
+ * Return the usage counter.
+ */
+ public int getUsed() {
+ return mUsed;
+ }
+
public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
int filterCallingUid, int userId, boolean resolveForStart,
@@ -4885,121 +4914,11 @@
*/
private final Object mSnapshotLock = new Object();
- // A counter of all queries that hit the current snapshot.
- @GuardedBy("mSnapshotLock")
- private int mSnapshotHits = 0;
-
- // A class to record snapshot statistics.
- private static class SnapshotStatistics {
- // A build time is "big" if it takes longer than 5ms.
- private static final long SNAPSHOT_BIG_BUILD_TIME_NS = TimeUnit.MILLISECONDS.toNanos(5);
-
- // A snapshot is in quick succession to the previous snapshot if it less than
- // 100ms since the previous snapshot.
- private static final long SNAPSHOT_QUICK_REBUILD_INTERVAL_NS =
- TimeUnit.MILLISECONDS.toNanos(100);
-
- // The interval between snapshot statistics logging, in ns.
- private static final long SNAPSHOT_LOG_INTERVAL_NS = TimeUnit.MINUTES.toNanos(10);
-
- // The throttle parameters for big build reporting. Do not report more than this
- // many events in a single log interval.
- private static final int SNAPSHOT_BUILD_REPORT_LIMIT = 10;
-
- // The time the snapshot statistics were last logged.
- private long mStatisticsSent = 0;
-
- // The number of build events logged since the last periodic log.
- private int mLoggedBuilds = 0;
-
- // The time of the last build.
- private long mLastBuildTime = 0;
-
- // The number of times the snapshot has been rebuilt since the statistics were
- // last logged.
- private int mRebuilds = 0;
-
- // The number of times the snapshot has been used since it was rebuilt.
- private int mReused = 0;
-
- // The number of "big" build times since the last log. "Big" is defined by
- // SNAPSHOT_BIG_BUILD_TIME.
- private int mBigBuilds = 0;
-
- // The number of quick rebuilds. "Quick" is defined by
- // SNAPSHOT_QUICK_REBUILD_INTERVAL_NS.
- private int mQuickRebuilds = 0;
-
- // The time take to build a snapshot. This is cumulative over the rebuilds recorded
- // in mRebuilds, so the average time to build a snapshot is given by
- // mBuildTimeNs/mRebuilds.
- private int mBuildTimeNs = 0;
-
- // The maximum build time since the last log.
- private long mMaxBuildTimeNs = 0;
-
- // The constant that converts ns to ms. This is the divisor.
- private final long NS_TO_MS = TimeUnit.MILLISECONDS.toNanos(1);
-
- // Convert ns to an int ms. The maximum range of this method is about 24 days.
- // There is no expectation that an event will take longer than that.
- private int nsToMs(long ns) {
- return (int) (ns / NS_TO_MS);
- }
-
- // The single method records a rebuild. The "now" parameter is passed in because
- // the caller needed it to computer the duration, so pass it in to avoid
- // recomputing it.
- private void rebuild(long now, long done, int hits) {
- if (mStatisticsSent == 0) {
- mStatisticsSent = now;
- }
- final long elapsed = now - mLastBuildTime;
- final long duration = done - now;
- mLastBuildTime = now;
-
- if (mMaxBuildTimeNs < duration) {
- mMaxBuildTimeNs = duration;
- }
- mRebuilds++;
- mReused += hits;
- mBuildTimeNs += duration;
-
- boolean log_build = false;
- if (duration > SNAPSHOT_BIG_BUILD_TIME_NS) {
- log_build = true;
- mBigBuilds++;
- }
- if (elapsed < SNAPSHOT_QUICK_REBUILD_INTERVAL_NS) {
- log_build = true;
- mQuickRebuilds++;
- }
- if (log_build && mLoggedBuilds < SNAPSHOT_BUILD_REPORT_LIMIT) {
- EventLogTags.writePmSnapshotRebuild(nsToMs(duration), nsToMs(elapsed));
- mLoggedBuilds++;
- }
-
- final long log_interval = now - mStatisticsSent;
- if (log_interval >= SNAPSHOT_LOG_INTERVAL_NS) {
- EventLogTags.writePmSnapshotStats(mRebuilds, mReused,
- mBigBuilds, mQuickRebuilds,
- nsToMs(mMaxBuildTimeNs),
- nsToMs(mBuildTimeNs));
- mStatisticsSent = now;
- mRebuilds = 0;
- mReused = 0;
- mBuildTimeNs = 0;
- mMaxBuildTimeNs = 0;
- mBigBuilds = 0;
- mQuickRebuilds = 0;
- mLoggedBuilds = 0;
- }
- }
- }
-
- // Snapshot statistics.
- @GuardedBy("mLock")
- private final SnapshotStatistics mSnapshotStatistics = new SnapshotStatistics();
+ /**
+ * The snapshot statistics. These are collected to track performance and to identify
+ * situations in which the snapshots are misbehaving.
+ */
+ private final SnapshotStatistics mSnapshotStatistics;
// The snapshot disable/enable switch. An image with the flag set true uses snapshots
// and an image with the flag set false does not use snapshots.
@@ -5033,10 +4952,9 @@
Computer c = mSnapshotComputer;
if (sSnapshotCorked && (c != null)) {
// Snapshots are corked, which means new ones should not be built right now.
+ c.use();
return c;
}
- // Deliberately capture the value pre-increment
- final int hits = mSnapshotHits++;
if (sSnapshotInvalid || (c == null)) {
// The snapshot is invalid if it is marked as invalid or if it is null. If it
// is null, then it is currently being rebuilt by rebuildSnapshot().
@@ -5046,7 +4964,7 @@
// self-consistent (the lock is being held) and is current as of the time
// this function is entered.
if (sSnapshotInvalid) {
- rebuildSnapshot(hits);
+ rebuildSnapshot();
}
// Guaranteed to be non-null. mSnapshotComputer is only be set to null
@@ -5056,6 +4974,7 @@
c = mSnapshotComputer;
}
}
+ c.use();
return c;
}
}
@@ -5065,16 +4984,16 @@
* threads from using the invalid computer until it is rebuilt.
*/
@GuardedBy("mLock")
- private void rebuildSnapshot(int hits) {
- final long now = System.nanoTime();
+ private void rebuildSnapshot() {
+ final long now = SystemClock.currentTimeMicro();
+ final int hits = mSnapshotComputer == null ? -1 : mSnapshotComputer.getUsed();
mSnapshotComputer = null;
sSnapshotInvalid = false;
final Snapshot args = new Snapshot(Snapshot.SNAPPED);
mSnapshotComputer = new ComputerEngine(args);
- final long done = System.nanoTime();
+ final long done = SystemClock.currentTimeMicro();
mSnapshotStatistics.rebuild(now, done, hits);
- mSnapshotHits = 0;
}
/**
@@ -6327,6 +6246,7 @@
mSnapshotEnabled = false;
mLiveComputer = createLiveComputer();
mSnapshotComputer = null;
+ mSnapshotStatistics = null;
mPackages.putAll(testParams.packages);
mEnableFreeCacheV2 = testParams.enableFreeCacheV2;
@@ -6479,17 +6399,20 @@
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mDomainVerificationManager.setConnection(mDomainVerificationConnection);
- // Create the computer as soon as the state objects have been installed. The
- // cached computer is the same as the live computer until the end of the
- // constructor, at which time the invalidation method updates it. The cache is
- // corked initially to ensure a cached computer is not built until the end of the
- // constructor.
- mSnapshotEnabled = SNAPSHOT_ENABLED;
- sSnapshotCorked = true;
- sSnapshotInvalid = true;
- mLiveComputer = createLiveComputer();
- mSnapshotComputer = null;
- registerObserver();
+ synchronized (mLock) {
+ // Create the computer as soon as the state objects have been installed. The
+ // cached computer is the same as the live computer until the end of the
+ // constructor, at which time the invalidation method updates it. The cache is
+ // corked initially to ensure a cached computer is not built until the end of the
+ // constructor.
+ mSnapshotEnabled = SNAPSHOT_ENABLED;
+ sSnapshotCorked = true;
+ sSnapshotInvalid = true;
+ mSnapshotStatistics = new SnapshotStatistics();
+ mLiveComputer = createLiveComputer();
+ mSnapshotComputer = null;
+ registerObserver();
+ }
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
@@ -15315,9 +15238,8 @@
final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions(
REASON_LOCKED_BOOT_COMPLETED);
am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(),
- false, false,
- userId);
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ bOptions.toBundle(), false, false, userId);
// Deliver BOOT_COMPLETED only if user is unlocked
final UserManagerInternal umInternal = mInjector.getUserManagerInternal();
@@ -15327,9 +15249,8 @@
bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(),
- false, false,
- userId);
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE,
+ bOptions.toBundle(), false, false, userId);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -22197,7 +22118,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
am.broadcastIntentWithFeature(null, null, intent, null, null,
- 0, null, null, null, android.app.AppOpsManager.OP_NONE,
+ 0, null, null, null, null, android.app.AppOpsManager.OP_NONE,
null, false, false, userId);
} catch (RemoteException e) {
}
@@ -23959,6 +23880,7 @@
pw.println(" dexopt: dump dexopt state");
pw.println(" compiler-stats: dump compiler statistics");
pw.println(" service-permissions: dump permissions required by services");
+ pw.println(" snapshot: dump snapshot statistics");
pw.println(" known-packages: dump known packages");
pw.println(" <package.name>: info about given package");
return;
@@ -24107,6 +24029,8 @@
dumpState.setDump(DumpState.DUMP_KNOWN_PACKAGES);
} else if ("t".equals(cmd) || "timeouts".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PER_UID_READ_TIMEOUTS);
+ } else if ("snapshot".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_SNAPSHOT_STATISTICS);
} else if ("write".equals(cmd)) {
synchronized (mLock) {
writeSettingsLPrTEMP();
@@ -24435,6 +24359,22 @@
pw.println(")");
}
}
+
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) {
+ pw.println("Snapshot statistics");
+ if (!mSnapshotEnabled) {
+ pw.println(" Snapshots disabled");
+ } else {
+ int hits = 0;
+ synchronized (mSnapshotLock) {
+ if (mSnapshotComputer != null) {
+ hits = mSnapshotComputer.getUsed();
+ }
+ }
+ final long now = SystemClock.currentTimeMicro();
+ mSnapshotStatistics.dump(pw, " ", now, hits, true);
+ }
+ }
}
/**
@@ -27810,8 +27750,8 @@
};
try {
am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null,
- requiredPermissions, android.app.AppOpsManager.OP_NONE, null, false, false,
- UserHandle.USER_ALL);
+ requiredPermissions, null, android.app.AppOpsManager.OP_NONE, null, false,
+ false, UserHandle.USER_ALL);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 4823c29..24f3930 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -117,6 +117,7 @@
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationPersistence;
import com.android.server.utils.Snappable;
+import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
@@ -165,11 +166,6 @@
private static final String TAG = "PackageSettings";
/**
- * Cached snapshot
- */
- private volatile Settings mSnapshot = null;
-
- /**
* Watchable machinery
*/
private final WatchableImpl mWatchable = new WatchableImpl();
@@ -212,7 +208,6 @@
* @param what The {@link Watchable} that generated the event.
*/
public void dispatchChange(@Nullable Watchable what) {
- mSnapshot = null;
mWatchable.dispatchChange(what);
}
/**
@@ -523,6 +518,19 @@
}
};
+ private final SnapshotCache<Settings> mSnapshot;
+
+ // Create a snapshot cache
+ private SnapshotCache<Settings> makeCache() {
+ return new SnapshotCache<Settings>(this, this) {
+ @Override
+ public Settings createSnapshot() {
+ Settings s = new Settings(mSource);
+ s.mWatchable.seal();
+ return s;
+ }};
+ }
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public Settings(Map<String, PackageSetting> pkgSettings) {
mLock = new PackageManagerTracedLock();
@@ -557,6 +565,8 @@
mDefaultBrowserApp.registerObserver(mObserver);
Watchable.verifyWatchedAttributes(this, mObserver);
+
+ mSnapshot = makeCache();
}
Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
@@ -608,6 +618,8 @@
mDefaultBrowserApp.registerObserver(mObserver);
Watchable.verifyWatchedAttributes(this, mObserver);
+
+ mSnapshot = makeCache();
}
/**
@@ -661,22 +673,15 @@
mPermissions = r.mPermissions;
mPermissionDataProvider = r.mPermissionDataProvider;
- // Do not register any Watchables
+ // Do not register any Watchables and do not create a snapshot cache.
+ mSnapshot = null;
}
/**
- * Return a snapshot. If the cached snapshot is null, build a new one. The logic in
- * the function ensures that this function returns a valid snapshot even if a race
- * condition causes the cached snapshot to be cleared asynchronously to this method.
+ * Return a snapshot.
*/
public Settings snapshot() {
- Settings s = mSnapshot;
- if (s == null) {
- s = new Settings(this);
- s.mWatchable.seal();
- mSnapshot = s;
- }
- return s;
+ return mSnapshot.snapshot();
}
private void invalidatePackageCache() {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index e222df0..c462a6c 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -264,7 +264,7 @@
public ShortcutInfo findShortcutById(@Nullable final String id) {
if (id == null) return null;
final List<ShortcutInfo> ret = getShortcutById(Collections.singleton(id));
- return ret.isEmpty() ? null : ret.get(0);
+ return (ret == null || ret.isEmpty()) ? null : ret.get(0);
}
public boolean isShortcutExistsAndInvisibleToPublisher(String id) {
@@ -2361,7 +2361,7 @@
});
}
- @NonNull
+ @Nullable
private List<ShortcutInfo> getShortcutById(@NonNull final Collection<String> ids) {
final List<String> shortcutIds = new ArrayList<>(1);
for (String id : ids) {
@@ -2525,7 +2525,8 @@
private AndroidFuture<AppSearchSession> setupSchema(
@NonNull final AppSearchSession session) {
SetSchemaRequest.Builder schemaBuilder = new SetSchemaRequest.Builder()
- .addSchemas(AppSearchPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA);
+ .addSchemas(AppSearchPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA)
+ .setForceOverride(true);
for (PackageIdentifier pi : mPackageIdentifiers.values()) {
schemaBuilder = schemaBuilder
.setSchemaTypeVisibilityForPackage(
diff --git a/services/core/java/com/android/server/pm/SnapshotStatistics.java b/services/core/java/com/android/server/pm/SnapshotStatistics.java
new file mode 100644
index 0000000..c425bad5
--- /dev/null
+++ b/services/core/java/com/android/server/pm/SnapshotStatistics.java
@@ -0,0 +1,622 @@
+/*
+ * 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.pm;
+
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.text.TextUtils;
+
+import com.android.server.EventLogTags;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * This class records statistics about PackageManagerService snapshots. It maintains two sets of
+ * statistics: a periodic set which represents the last 10 minutes, and a cumulative set since
+ * process boot. The key metrics that are recorded are:
+ * <ul>
+ * <li> The time to create a snapshot - this is the performance cost of a snapshot
+ * <li> The lifetime of the snapshot - creation time over lifetime is the amortized cost
+ * <li> The number of times a snapshot is reused - this is the number of times lock
+ * contention was avoided.
+ * </ul>
+
+ * The time conversions in this class are designed to keep arithmetic using ints, rather
+ * than longs. Raw times are supplied as longs in units of us. These are left long.
+ * Rebuild durations however, are converted to ints. An int can express a duration of
+ * approximately 35 minutes. This is longer than any expected snapshot rebuild time, so
+ * an int is satisfactory. The exception is the cumulative rebuild time over the course
+ * of a monitoring cycle: this value is kept long since the cycle time is one week and in
+ * a badly behaved system, the rebuild time might exceed 35 minutes.
+
+ * @hide
+ */
+public class SnapshotStatistics {
+ /**
+ * The interval at which statistics should be ticked. It is 60s. The interval is in
+ * units of milliseconds because that is what's required by Handler.sendMessageDelayed().
+ */
+ public static final int SNAPSHOT_TICK_INTERVAL_MS = 60 * 1000;
+
+ /**
+ * The number of ticks for long statistics. This is one week.
+ */
+ public static final int SNAPSHOT_LONG_TICKS = 7 * 24 * 60;
+
+ /**
+ * The number snapshot event logs that can be generated in a single logging interval.
+ * A small number limits the logging generated by this class. A snapshot event log is
+ * generated for every big snapshot build time, up to the limit, or whenever the
+ * maximum build time is exceeded in the logging interval.
+ */
+ public static final int SNAPSHOT_BUILD_REPORT_LIMIT = 10;
+
+ /**
+ * The number of microseconds in a millisecond.
+ */
+ private static final int US_IN_MS = 1000;
+
+ /**
+ * A snapshot build time is "big" if it takes longer than 10ms.
+ */
+ public static final int SNAPSHOT_BIG_BUILD_TIME_US = 10 * US_IN_MS;
+
+ /**
+ * A snapshot build time is reportable if it takes longer than 30ms. Testing shows
+ * that this is very rare.
+ */
+ public static final int SNAPSHOT_REPORTABLE_BUILD_TIME_US = 30 * US_IN_MS;
+
+ /**
+ * A snapshot is short-lived it used fewer than 5 times.
+ */
+ public static final int SNAPSHOT_SHORT_LIFETIME = 5;
+
+ /**
+ * The lock to control access to this object.
+ */
+ private final Object mLock = new Object();
+
+ /**
+ * The bins for the build time histogram. Values are in us.
+ */
+ private final BinMap mTimeBins;
+
+ /**
+ * The bins for the snapshot use histogram.
+ */
+ private final BinMap mUseBins;
+
+ /**
+ * The number of events reported in the current tick.
+ */
+ private int mEventsReported = 0;
+
+ /**
+ * The tick counter. At the default tick interval, this wraps every 4000 years or so.
+ */
+ private int mTicks = 0;
+
+ /**
+ * The handler used for the periodic ticks.
+ */
+ private Handler mHandler = null;
+
+ /**
+ * Convert ns to an int ms. The maximum range of this method is about 24 days. There
+ * is no expectation that an event will take longer than that.
+ */
+ private int usToMs(int us) {
+ return us / US_IN_MS;
+ }
+
+ /**
+ * This class exists to provide a fast bin lookup for histograms. An instance has an
+ * integer array that maps incoming values to bins. Values larger than the array are
+ * mapped to the top-most bin.
+ */
+ private static class BinMap {
+
+ // The number of bins
+ private int mCount;
+ // The mapping of low integers to bins
+ private int[] mBinMap;
+ // The maximum mapped value. Values at or above this are mapped to the
+ // top bin.
+ private int mMaxBin;
+ // A copy of the original key
+ private int[] mUserKey;
+
+ /**
+ * Create a bin map. The input is an array of integers, which must be
+ * monotonically increasing (this is not checked). The result is an integer array
+ * as long as the largest value in the input.
+ */
+ BinMap(int[] userKey) {
+ mUserKey = Arrays.copyOf(userKey, userKey.length);
+ // The number of bins is the length of the keys, plus 1 (for the max).
+ mCount = mUserKey.length + 1;
+ // The maximum value is one more than the last one in the map.
+ mMaxBin = mUserKey[mUserKey.length - 1] + 1;
+ mBinMap = new int[mMaxBin + 1];
+
+ int j = 0;
+ for (int i = 0; i < mUserKey.length; i++) {
+ while (j <= mUserKey[i]) {
+ mBinMap[j] = i;
+ j++;
+ }
+ }
+ mBinMap[mMaxBin] = mUserKey.length;
+ }
+
+ /**
+ * Map a value to a bin.
+ */
+ public int getBin(int x) {
+ if (x >= 0 && x < mMaxBin) {
+ return mBinMap[x];
+ } else if (x >= mMaxBin) {
+ return mBinMap[mMaxBin];
+ } else {
+ // x is negative. The bin will not be used.
+ return 0;
+ }
+ }
+
+ /**
+ * The number of bins in this map
+ */
+ public int count() {
+ return mCount;
+ }
+
+ /**
+ * For convenience, return the user key.
+ */
+ public int[] userKeys() {
+ return mUserKey;
+ }
+ }
+
+ /**
+ * A complete set of statistics. These are public, making it simpler for a client to
+ * fetch the individual fields.
+ */
+ public class Stats {
+
+ /**
+ * The start time for this set of statistics, in us.
+ */
+ public long mStartTimeUs = 0;
+
+ /**
+ * The completion time for this set of statistics, in ns. A value of zero means
+ * the statistics are still active.
+ */
+ public long mStopTimeUs = 0;
+
+ /**
+ * The build-time histogram. The total number of rebuilds is the sum over the
+ * histogram entries.
+ */
+ public int[] mTimes;
+
+ /**
+ * The reuse histogram. The total number of snapshot uses is the sum over the
+ * histogram entries.
+ */
+ public int[] mUsed;
+
+ /**
+ * The total number of rebuilds. This could be computed by summing over the use
+ * bins, but is maintained separately for convenience.
+ */
+ public int mTotalBuilds = 0;
+
+ /**
+ * The total number of times any snapshot was used.
+ */
+ public int mTotalUsed = 0;
+
+ /**
+ * The total number of builds that count as big, which means they took longer than
+ * SNAPSHOT_BIG_BUILD_TIME_NS.
+ */
+ public int mBigBuilds = 0;
+
+ /**
+ * The total number of short-lived snapshots
+ */
+ public int mShortLived = 0;
+
+ /**
+ * The time taken to build snapshots. This is cumulative over the rebuilds
+ * recorded in mRebuilds, so the average time to build a snapshot is given by
+ * mBuildTimeNs/mRebuilds. Note that this cannot be computed from the histogram.
+ */
+ public long mTotalTimeUs = 0;
+
+ /**
+ * The maximum build time since the last log.
+ */
+ public int mMaxBuildTimeUs = 0;
+
+ /**
+ * Record the rebuild. The parameters are the length of time it took to build the
+ * latest snapshot, and the number of times the _previous_ snapshot was used. A
+ * negative value for used signals an invalid value, which is the case the first
+ * time a snapshot is every built.
+ */
+ private void rebuild(int duration, int used,
+ int buildBin, int useBin, boolean big, boolean quick) {
+ mTotalBuilds++;
+ mTimes[buildBin]++;
+
+ if (used >= 0) {
+ mTotalUsed += used;
+ mUsed[useBin]++;
+ }
+
+ mTotalTimeUs += duration;
+ boolean reportIt = false;
+
+ if (big) {
+ mBigBuilds++;
+ }
+ if (quick) {
+ mShortLived++;
+ }
+ if (mMaxBuildTimeUs < duration) {
+ mMaxBuildTimeUs = duration;
+ }
+ }
+
+ private Stats(long now) {
+ mStartTimeUs = now;
+ mTimes = new int[mTimeBins.count()];
+ mUsed = new int[mUseBins.count()];
+ }
+
+ /**
+ * Create a copy of the argument. The copy is made under lock but can then be
+ * used without holding the lock.
+ */
+ private Stats(Stats orig) {
+ mStartTimeUs = orig.mStartTimeUs;
+ mStopTimeUs = orig.mStopTimeUs;
+ mTimes = Arrays.copyOf(orig.mTimes, orig.mTimes.length);
+ mUsed = Arrays.copyOf(orig.mUsed, orig.mUsed.length);
+ mTotalBuilds = orig.mTotalBuilds;
+ mTotalUsed = orig.mTotalUsed;
+ mBigBuilds = orig.mBigBuilds;
+ mShortLived = orig.mShortLived;
+ mTotalTimeUs = orig.mTotalTimeUs;
+ mMaxBuildTimeUs = orig.mMaxBuildTimeUs;
+ }
+
+ /**
+ * Set the end time for the statistics. The end time is used only for reporting
+ * in the dump() method.
+ */
+ private void complete(long stop) {
+ mStopTimeUs = stop;
+ }
+
+ /**
+ * Format a time span into ddd:HH:MM:SS. The input is in us.
+ */
+ private String durationToString(long us) {
+ // s has a range of several years
+ int s = (int) (us / (1000 * 1000));
+ int m = s / 60;
+ s %= 60;
+ int h = m / 60;
+ m %= 60;
+ int d = h / 24;
+ h %= 24;
+ if (d != 0) {
+ return TextUtils.formatSimple("%2d:%02d:%02d:%02d", d, h, m, s);
+ } else if (h != 0) {
+ return TextUtils.formatSimple("%2s %02d:%02d:%02d", "", h, m, s);
+ } else {
+ return TextUtils.formatSimple("%2s %2s %2d:%02d", "", "", m, s);
+ }
+ }
+
+ /**
+ * Print the prefix for dumping. This does not generate a line to the output.
+ */
+ private void dumpPrefix(PrintWriter pw, String indent, long now, boolean header,
+ String title) {
+ pw.print(indent + " ");
+ if (header) {
+ pw.format(Locale.US, "%-23s", title);
+ } else {
+ pw.format(Locale.US, "%11s", durationToString(now - mStartTimeUs));
+ if (mStopTimeUs != 0) {
+ pw.format(Locale.US, " %11s", durationToString(now - mStopTimeUs));
+ } else {
+ pw.format(Locale.US, " %11s", "now");
+ }
+ }
+ }
+
+ /**
+ * Dump the summary statistics record. Choose the header or the data.
+ * number of builds
+ * number of uses
+ * number of big builds
+ * number of short lifetimes
+ * cumulative build time, in seconds
+ * maximum build time, in ms
+ */
+ private void dumpStats(PrintWriter pw, String indent, long now, boolean header) {
+ dumpPrefix(pw, indent, now, header, "Summary stats");
+ if (header) {
+ pw.format(Locale.US, " %10s %10s %10s %10s %10s %10s",
+ "TotBlds", "TotUsed", "BigBlds", "ShortLvd",
+ "TotTime", "MaxTime");
+ } else {
+ pw.format(Locale.US,
+ " %10d %10d %10d %10d %10d %10d",
+ mTotalBuilds, mTotalUsed, mBigBuilds, mShortLived,
+ mTotalTimeUs / 1000, mMaxBuildTimeUs / 1000);
+ }
+ pw.println();
+ }
+
+ /**
+ * Dump the build time histogram. Choose the header or the data.
+ */
+ private void dumpTimes(PrintWriter pw, String indent, long now, boolean header) {
+ dumpPrefix(pw, indent, now, header, "Build times");
+ if (header) {
+ int[] keys = mTimeBins.userKeys();
+ for (int i = 0; i < keys.length; i++) {
+ pw.format(Locale.US, " %10s",
+ TextUtils.formatSimple("<= %dms", keys[i]));
+ }
+ pw.format(Locale.US, " %10s",
+ TextUtils.formatSimple("> %dms", keys[keys.length - 1]));
+ } else {
+ for (int i = 0; i < mTimes.length; i++) {
+ pw.format(Locale.US, " %10d", mTimes[i]);
+ }
+ }
+ pw.println();
+ }
+
+ /**
+ * Dump the usage histogram. Choose the header or the data.
+ */
+ private void dumpUsage(PrintWriter pw, String indent, long now, boolean header) {
+ dumpPrefix(pw, indent, now, header, "Use counters");
+ if (header) {
+ int[] keys = mUseBins.userKeys();
+ for (int i = 0; i < keys.length; i++) {
+ pw.format(Locale.US, " %10s", TextUtils.formatSimple("<= %d", keys[i]));
+ }
+ pw.format(Locale.US, " %10s",
+ TextUtils.formatSimple("> %d", keys[keys.length - 1]));
+ } else {
+ for (int i = 0; i < mUsed.length; i++) {
+ pw.format(Locale.US, " %10d", mUsed[i]);
+ }
+ }
+ pw.println();
+ }
+
+ /**
+ * Dump something, based on the "what" parameter.
+ */
+ private void dump(PrintWriter pw, String indent, long now, boolean header, String what) {
+ if (what.equals("stats")) {
+ dumpStats(pw, indent, now, header);
+ } else if (what.equals("times")) {
+ dumpTimes(pw, indent, now, header);
+ } else if (what.equals("usage")) {
+ dumpUsage(pw, indent, now, header);
+ } else {
+ throw new IllegalArgumentException("unrecognized choice: " + what);
+ }
+ }
+
+ /**
+ * Report the object via an event. Presumably the record indicates an anomalous
+ * incident.
+ */
+ private void report() {
+ EventLogTags.writePmSnapshotStats(
+ mTotalBuilds, mTotalUsed, mBigBuilds, mShortLived,
+ mMaxBuildTimeUs / US_IN_MS, mTotalTimeUs / US_IN_MS);
+ }
+ }
+
+ /**
+ * Long statistics. These roll over approximately every week.
+ */
+ private Stats[] mLong;
+
+ /**
+ * Short statistics. These roll over approximately every minute;
+ */
+ private Stats[] mShort;
+
+ /**
+ * The time of the last build. This can be used to compute the length of time a
+ * snapshot existed before being replaced.
+ */
+ private long mLastBuildTime = 0;
+
+ /**
+ * Create a snapshot object. Initialize the bin levels. The last bin catches
+ * everything that is not caught earlier, so its value is not really important.
+ */
+ public SnapshotStatistics() {
+ // Create the bin thresholds. The time bins are in units of us.
+ mTimeBins = new BinMap(new int[] { 1, 2, 5, 10, 20, 50, 100 });
+ mUseBins = new BinMap(new int[] { 1, 2, 5, 10, 20, 50, 100 });
+
+ // Create the raw statistics
+ final long now = SystemClock.currentTimeMicro();
+ mLong = new Stats[2];
+ mLong[0] = new Stats(now);
+ mShort = new Stats[10];
+ mShort[0] = new Stats(now);
+
+ // Create the message handler for ticks and start the ticker.
+ mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ SnapshotStatistics.this.handleMessage(msg);
+ }
+ };
+ scheduleTick();
+ }
+
+ /**
+ * Handle a message. The only messages are ticks, so the message parameter is ignored.
+ */
+ private void handleMessage(@Nullable Message msg) {
+ tick();
+ scheduleTick();
+ }
+
+ /**
+ * Schedule one tick, a tick interval in the future.
+ */
+ private void scheduleTick() {
+ mHandler.sendEmptyMessageDelayed(0, SNAPSHOT_TICK_INTERVAL_MS);
+ }
+
+ /**
+ * Record a rebuild. Cumulative and current statistics are updated. Events may be
+ * generated.
+ * @param now The time at which the snapshot rebuild began, in ns.
+ * @param done The time at which the snapshot rebuild completed, in ns.
+ * @param hits The number of times the previous snapshot was used.
+ */
+ public void rebuild(long now, long done, int hits) {
+ // The duration has a span of about 2000s
+ final int duration = (int) (done - now);
+ boolean reportEvent = false;
+ synchronized (mLock) {
+ mLastBuildTime = now;
+
+ final int timeBin = mTimeBins.getBin(duration / 1000);
+ final int useBin = mUseBins.getBin(hits);
+ final boolean big = duration >= SNAPSHOT_BIG_BUILD_TIME_US;
+ final boolean quick = hits <= SNAPSHOT_SHORT_LIFETIME;
+
+ mShort[0].rebuild(duration, hits, timeBin, useBin, big, quick);
+ mLong[0].rebuild(duration, hits, timeBin, useBin, big, quick);
+ if (duration >= SNAPSHOT_REPORTABLE_BUILD_TIME_US) {
+ if (mEventsReported++ < SNAPSHOT_BUILD_REPORT_LIMIT) {
+ reportEvent = true;
+ }
+ }
+ }
+ // The IO to the logger is done outside the lock.
+ if (reportEvent) {
+ // Report the first N big builds, and every new maximum after that.
+ EventLogTags.writePmSnapshotRebuild(duration / US_IN_MS, hits);
+ }
+ }
+
+ /**
+ * Roll a stats array. Shift the elements up an index and create a new element at
+ * index zero. The old element zero is completed with the specified time.
+ */
+ private void shift(Stats[] s, long now) {
+ s[0].complete(now);
+ for (int i = s.length - 1; i > 0; i--) {
+ s[i] = s[i - 1];
+ }
+ s[0] = new Stats(now);
+ }
+
+ /**
+ * Roll the statistics.
+ * <ul>
+ * <li> Roll the quick statistics immediately.
+ * <li> Roll the long statistics every SNAPSHOT_LONG_TICKER ticks. The long
+ * statistics hold a week's worth of data.
+ * <li> Roll the logging statistics every SNAPSHOT_LOGGING_TICKER ticks. The logging
+ * statistics hold 10 minutes worth of data.
+ * </ul>
+ */
+ private void tick() {
+ synchronized (mLock) {
+ long now = SystemClock.currentTimeMicro();
+ mTicks++;
+ if (mTicks % SNAPSHOT_LONG_TICKS == 0) {
+ shift(mLong, now);
+ }
+ shift(mShort, now);
+ mEventsReported = 0;
+ }
+ }
+
+ /**
+ * Dump the statistics. The header is dumped from l[0], so that must not be null.
+ */
+ private void dump(PrintWriter pw, String indent, long now, Stats[] l, Stats[] s, String what) {
+ l[0].dump(pw, indent, now, true, what);
+ for (int i = 0; i < s.length; i++) {
+ if (s[i] != null) {
+ s[i].dump(pw, indent, now, false, what);
+ }
+ }
+ for (int i = 0; i < l.length; i++) {
+ if (l[i] != null) {
+ l[i].dump(pw, indent, now, false, what);
+ }
+ }
+ }
+
+ /**
+ * Dump the statistics. The format is compatible with the PackageManager dumpsys
+ * output.
+ */
+ public void dump(PrintWriter pw, String indent, long now, int unrecorded, boolean full) {
+ // Grab the raw statistics under lock, but print them outside of the lock.
+ Stats[] l;
+ Stats[] s;
+ synchronized (mLock) {
+ l = Arrays.copyOf(mLong, mLong.length);
+ l[0] = new Stats(l[0]);
+ s = Arrays.copyOf(mShort, mShort.length);
+ s[0] = new Stats(s[0]);
+ }
+ pw.format(Locale.US, "%s Unrecorded hits %d", indent, unrecorded);
+ pw.println();
+ dump(pw, indent, now, l, s, "stats");
+ if (!full) {
+ return;
+ }
+ pw.println();
+ dump(pw, indent, now, l, s, "times");
+ pw.println();
+ dump(pw, indent, now, l, s, "usage");
+ }
+}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index e913829..81cfbf7 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -85,6 +85,15 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
}
]
+ },
+ {
+ "name": "PackageManagerServiceHostTests",
+ "file_patterns": ["AppsFilter\\.java"],
+ "options": [
+ {
+ "include-filter": "com.android.server.pm.test.OverlayActorVisibilityTest"
+ }
+ ]
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/pm/WatchedIntentFilter.java b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
new file mode 100644
index 0000000..30f276e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
@@ -0,0 +1,715 @@
+/*
+ * 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.pm;
+
+import android.annotation.NonNull;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.PatternMatcher;
+import android.util.Printer;
+
+import com.android.server.utils.Snappable;
+import com.android.server.utils.WatchableImpl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * A watched variant of {@link IntentFilter}. The class consists of a
+ * {@link IntentFilter} attribute and methods that are identical to those in IntentFilter,
+ * forwarding to the attribute.
+ *
+ * @hide
+ */
+public class WatchedIntentFilter
+ extends WatchableImpl
+ implements Snappable<WatchedIntentFilter> {
+
+ // Watch for modifications made through an {@link Iterator}.
+ private class WatchedIterator<E> implements Iterator<E> {
+ private final Iterator<E> mIterator;
+ WatchedIterator(@NonNull Iterator<E> i) {
+ mIterator = i;
+ }
+ public boolean hasNext() {
+ return mIterator.hasNext();
+ }
+ public E next() {
+ return mIterator.next();
+ }
+ public void remove() {
+ mIterator.remove();
+ WatchedIntentFilter.this.onChanged();
+ }
+ public void forEachRemaining(Consumer<? super E> action) {
+ mIterator.forEachRemaining(action);
+ WatchedIntentFilter.this.onChanged();
+ }
+ }
+
+ // A convenience function to wrap an iterator result, but only if it is not null.
+ private <E> Iterator<E> maybeWatch(Iterator<E> i) {
+ return i == null ? i : new WatchedIterator<>(i);
+ }
+
+ // The wrapped {@link IntentFilter}
+ protected IntentFilter mFilter;
+
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ protected WatchedIntentFilter() {
+ mFilter = new IntentFilter();
+ }
+
+ // Convert an {@link IntentFilter} to a {@link WatchedIntentFilter}
+ protected WatchedIntentFilter(IntentFilter f) {
+ mFilter = new IntentFilter(f);
+ }
+
+ // The copy constructor is used to create a snapshot of the object.
+ protected WatchedIntentFilter(WatchedIntentFilter f) {
+ this(f.getIntentFilter());
+ }
+
+ /**
+ * Create a WatchedIntentFilter based on an action
+ * @see IntentFilter#IntentFilter(String)
+ */
+ public WatchedIntentFilter(String action) {
+ mFilter = new IntentFilter(action);
+ }
+
+ /**
+ * Create a WatchedIntentFilter based on an action and a data type.
+ * @see IntentFilter#IntentFilter(String, String)
+ */
+ public WatchedIntentFilter(String action, String dataType)
+ throws IntentFilter.MalformedMimeTypeException {
+ mFilter = new IntentFilter(action, dataType);
+ }
+
+ /**
+ * Return a clone of the filter represented by this object.
+ */
+ public WatchedIntentFilter cloneFilter() {
+ return new WatchedIntentFilter(mFilter);
+ }
+
+ /**
+ * Return the {@link IntentFilter} represented by this object.
+ */
+ public IntentFilter getIntentFilter() {
+ return mFilter;
+ }
+
+ /**
+ * @see IntentFilter#setPriority(int)
+ */
+ public final void setPriority(int priority) {
+ mFilter.setPriority(priority);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#getPriority()
+ */
+ public final int getPriority() {
+ return mFilter.getPriority();
+ }
+
+ /**
+ * @see IntentFilter#setOrder(int)
+ */
+ public final void setOrder(int order) {
+ mFilter.setOrder(order);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#getOrder()
+ */
+ public final int getOrder() {
+ return mFilter.getOrder();
+ }
+
+ /**
+ * @see IntentFilter#getAutoVerify()
+ */
+ public final boolean getAutoVerify() {
+ return mFilter.getAutoVerify();
+ }
+
+ /**
+ * @see IntentFilter#handleAllWebDataURI()
+ */
+ public final boolean handleAllWebDataURI() {
+ return mFilter.handleAllWebDataURI();
+ }
+
+ /**
+ * @see IntentFilter#handlesWebUris(boolean)
+ */
+ public final boolean handlesWebUris(boolean onlyWebSchemes) {
+ return mFilter.handlesWebUris(onlyWebSchemes);
+ }
+
+ /**
+ * @see IntentFilter#needsVerification()
+ */
+ public final boolean needsVerification() {
+ return mFilter.needsVerification();
+ }
+
+ /**
+ * @see IntentFilter#setVerified(boolean)
+ */
+ public void setVerified(boolean verified) {
+ mFilter.setVerified(verified);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#setVisibilityToInstantApp(int)
+ */
+ public void setVisibilityToInstantApp(int visibility) {
+ mFilter.setVisibilityToInstantApp(visibility);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#getVisibilityToInstantApp()
+ */
+ public int getVisibilityToInstantApp() {
+ return mFilter.getVisibilityToInstantApp();
+ }
+
+ /**
+ * @see IntentFilter#isVisibleToInstantApp()
+ */
+ public boolean isVisibleToInstantApp() {
+ return mFilter.isVisibleToInstantApp();
+ }
+
+ /**
+ * @see IntentFilter#isExplicitlyVisibleToInstantApp()
+ */
+ public boolean isExplicitlyVisibleToInstantApp() {
+ return mFilter.isExplicitlyVisibleToInstantApp();
+ }
+
+ /**
+ * @see IntentFilter#isImplicitlyVisibleToInstantApp()
+ */
+ public boolean isImplicitlyVisibleToInstantApp() {
+ return mFilter.isImplicitlyVisibleToInstantApp();
+ }
+
+ /**
+ * @see IntentFilter#addAction(String)
+ */
+ public final void addAction(String action) {
+ mFilter.addAction(action);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#countActions()
+ */
+ public final int countActions() {
+ return mFilter.countActions();
+ }
+
+ /**
+ * @see IntentFilter#getAction(int)
+ */
+ public final String getAction(int index) {
+ return mFilter.getAction(index);
+ }
+
+ /**
+ * @see IntentFilter#hasAction(String)
+ */
+ public final boolean hasAction(String action) {
+ return mFilter.hasAction(action);
+ }
+
+ /**
+ * @see IntentFilter#matchAction(String)
+ */
+ public final boolean matchAction(String action) {
+ return mFilter.matchAction(action);
+ }
+
+ /**
+ * @see IntentFilter#actionsIterator()
+ */
+ public final Iterator<String> actionsIterator() {
+ return maybeWatch(mFilter.actionsIterator());
+ }
+
+ /**
+ * @see IntentFilter#addDataType(String)
+ */
+ public final void addDataType(String type)
+ throws IntentFilter.MalformedMimeTypeException {
+ mFilter.addDataType(type);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#addDynamicDataType(String)
+ */
+ public final void addDynamicDataType(String type)
+ throws IntentFilter.MalformedMimeTypeException {
+ mFilter.addDynamicDataType(type);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#clearDynamicDataTypes()
+ */
+ public final void clearDynamicDataTypes() {
+ mFilter.clearDynamicDataTypes();
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#countStaticDataTypes()
+ */
+ public int countStaticDataTypes() {
+ return mFilter.countStaticDataTypes();
+ }
+
+ /**
+ * @see IntentFilter#hasDataType(String)
+ */
+ public final boolean hasDataType(String type) {
+ return mFilter.hasDataType(type);
+ }
+
+ /**
+ * @see IntentFilter#hasExactDynamicDataType(String)
+ */
+ public final boolean hasExactDynamicDataType(String type) {
+ return mFilter.hasExactDynamicDataType(type);
+ }
+
+ /**
+ * @see IntentFilter#hasExactStaticDataType(String)
+ */
+ public final boolean hasExactStaticDataType(String type) {
+ return mFilter.hasExactStaticDataType(type);
+ }
+
+ /**
+ * @see IntentFilter#countDataTypes()
+ */
+ public final int countDataTypes() {
+ return mFilter.countDataTypes();
+ }
+
+ /**
+ * @see IntentFilter#getDataType(int)
+ */
+ public final String getDataType(int index) {
+ return mFilter.getDataType(index);
+ }
+
+ /**
+ * @see IntentFilter#typesIterator()
+ */
+ public final Iterator<String> typesIterator() {
+ return maybeWatch(mFilter.typesIterator());
+ }
+
+ /**
+ /**
+ * @see IntentFilter#dataTypes()
+ */
+ public final List<String> dataTypes() {
+ return mFilter.dataTypes();
+ }
+
+ /**
+ * @see IntentFilter#addMimeGroup(String)
+ */
+ public final void addMimeGroup(String name) {
+ mFilter.addMimeGroup(name);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#hasMimeGroup(String)
+ */
+ public final boolean hasMimeGroup(String name) {
+ return mFilter.hasMimeGroup(name);
+ }
+
+ /**
+ * @see IntentFilter#getMimeGroup(int)
+ */
+ public final String getMimeGroup(int index) {
+ return mFilter.getMimeGroup(index);
+ }
+
+ /**
+ * @see IntentFilter#countMimeGroups()
+ */
+ public final int countMimeGroups() {
+ return mFilter.countMimeGroups();
+ }
+
+ /**
+ * @see IntentAction@mimeGroupsIterator()
+ */
+ public final Iterator<String> mimeGroupsIterator() {
+ return maybeWatch(mFilter.mimeGroupsIterator());
+ }
+
+ /**
+ * @see IntentFilter#addDataScheme(String)
+ */
+ public final void addDataScheme(String scheme) {
+ mFilter.addDataScheme(scheme);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#countDataSchemes()
+ */
+ public final int countDataSchemes() {
+ return mFilter.countDataSchemes();
+ }
+
+ /**
+ * @see IntentFilter#getDataScheme(int)
+ */
+ public final String getDataScheme(int index) {
+ return mFilter.getDataScheme(index);
+ }
+
+ /**
+ * @see IntentFilter#hasDataScheme(String)
+ */
+ public final boolean hasDataScheme(String scheme) {
+ return mFilter.hasDataScheme(scheme);
+ }
+
+ /**
+ * @see IntentFilter#schemesIterator()
+ */
+ public final Iterator<String> schemesIterator() {
+ return maybeWatch(mFilter.schemesIterator());
+ }
+
+ /**
+ * @see IntentFilter#addDataSchemeSpecificPart(String, int)
+ */
+ public final void addDataSchemeSpecificPart(String ssp, int type) {
+ mFilter.addDataSchemeSpecificPart(ssp, type);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#addDataSchemeSpecificPart(PatternMatcher)
+ */
+ public final void addDataSchemeSpecificPart(PatternMatcher ssp) {
+ mFilter.addDataSchemeSpecificPart(ssp);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#countDataSchemeSpecificParts()
+ */
+ public final int countDataSchemeSpecificParts() {
+ return mFilter.countDataSchemeSpecificParts();
+ }
+
+ /**
+ * @see IntentFilter#getDataSchemeSpecificPart(int)
+ */
+ public final PatternMatcher getDataSchemeSpecificPart(int index) {
+ return mFilter.getDataSchemeSpecificPart(index);
+ }
+
+ /**
+ * @see IntentFilter#hasDataSchemeSpecificPart(String)
+ */
+ public final boolean hasDataSchemeSpecificPart(String data) {
+ return mFilter.hasDataSchemeSpecificPart(data);
+ }
+
+ /**
+ * @see IntentFilter#schemeSpecificPartsIterator()
+ */
+ public final Iterator<PatternMatcher> schemeSpecificPartsIterator() {
+ return maybeWatch(mFilter.schemeSpecificPartsIterator());
+ }
+
+ /**
+ * @see IntentFilter#addDataAuthority(String, String)
+ */
+ public final void addDataAuthority(String host, String port) {
+ mFilter.addDataAuthority(host, port);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#addDataAuthority(IntentFilter.AuthorityEntry)
+ */
+ public final void addDataAuthority(IntentFilter.AuthorityEntry ent) {
+ mFilter.addDataAuthority(ent);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#countDataAuthorities()
+ */
+ public final int countDataAuthorities() {
+ return mFilter.countDataAuthorities();
+ }
+
+ /**
+ * @see IntentFilter#getDataAuthority(int)
+ */
+ public final IntentFilter.AuthorityEntry getDataAuthority(int index) {
+ return mFilter.getDataAuthority(index);
+ }
+
+ /**
+ * @see IntentFilter#hasDataAuthority(Uri)
+ */
+ public final boolean hasDataAuthority(Uri data) {
+ return mFilter.hasDataAuthority(data);
+ }
+
+ /**
+ * @see IntentFilter#authoritiesIterator()
+ */
+ public final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator() {
+ return maybeWatch(mFilter.authoritiesIterator());
+ }
+
+ /**
+ * @see IntentFilter#addDataPath(String, int)
+ */
+ public final void addDataPath(String path, int type) {
+ mFilter.addDataPath(path, type);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#addDataPath(PatternMatcher)
+ */
+ public final void addDataPath(PatternMatcher path) {
+ mFilter.addDataPath(path);
+ onChanged();
+ }
+
+ /**
+ * @see IntentFilter#countDataPaths()
+ */
+ public final int countDataPaths() {
+ return mFilter.countDataPaths();
+ }
+
+ /**
+ * @see IntentFilter#getDataPath(int)
+ */
+ public final PatternMatcher getDataPath(int index) {
+ return mFilter.getDataPath(index);
+ }
+
+ /**
+ * @see IntentFilter#hasDataPath(String)
+ */
+ public final boolean hasDataPath(String data) {
+ return mFilter.hasDataPath(data);
+ }
+
+ /**
+ * @see IntentFilter#pathsIterator()
+ */
+ public final Iterator<PatternMatcher> pathsIterator() {
+ return maybeWatch(mFilter.pathsIterator());
+ }
+
+ /**
+ * @see IntentFilter#matchDataAuthority(Uri)
+ */
+ public final int matchDataAuthority(Uri data) {
+ return mFilter.matchDataAuthority(data);
+ }
+
+ /**
+ * @see IntentFilter#matchDataAuthority(Uri, boolean)
+ */
+ public final int matchDataAuthority(Uri data, boolean wildcardSupported) {
+ return mFilter.matchDataAuthority(data, wildcardSupported);
+ }
+
+ /**
+ * @see IntentFilter#matchData(String, String, Uri)
+ */
+ public final int matchData(String type, String scheme, Uri data) {
+ return mFilter.matchData(type, scheme, data);
+ }
+
+ /**
+ * @see IntentFilter#addCategory(String)
+ */
+ public final void addCategory(String category) {
+ mFilter.addCategory(category);
+ }
+
+ /**
+ * @see IntentFilter#countCategories()
+ */
+ public final int countCategories() {
+ return mFilter.countCategories();
+ }
+
+ /**
+ * @see IntentFilter#getCategory(int)
+ */
+ public final String getCategory(int index) {
+ return mFilter.getCategory(index);
+ }
+
+ /**
+ * @see IntentFilter#hasCategory(String)
+ */
+ public final boolean hasCategory(String category) {
+ return mFilter.hasCategory(category);
+ }
+
+ /**
+ * @see IntentFilter#categoriesIterator()
+ */
+ public final Iterator<String> categoriesIterator() {
+ return maybeWatch(mFilter.categoriesIterator());
+ }
+
+ /**
+ * @see IntentFilter#matchCategories(Set<String>)
+ */
+ public final String matchCategories(Set<String> categories) {
+ return mFilter.matchCategories(categories);
+ }
+
+ /**
+ * @see IntentFilter#match(ContentResolver, Intent, boolean, String)
+ */
+ public final int match(ContentResolver resolver, Intent intent,
+ boolean resolve, String logTag) {
+ return mFilter.match(resolver, intent,
+ resolve, logTag);
+ }
+
+ /**
+ * @see IntentFilter#match(String, String, String, Uri, Set<String>, String)
+ */
+ public final int match(String action, String type, String scheme,
+ Uri data, Set<String> categories, String logTag) {
+ return mFilter.match(action, type, scheme,
+ data, categories, logTag);
+ }
+
+ /**
+ * @see IntentFilter#match(String, String, String, Uri, Set<String>, String, boolean,
+ Collection<String> ignoreActions)
+ */
+ public final int match(String action, String type, String scheme,
+ Uri data, Set<String> categories, String logTag, boolean supportWildcards,
+ Collection<String> ignoreActions) {
+ return mFilter.match(action, type, scheme,
+ data, categories, logTag, supportWildcards,
+ ignoreActions);
+ }
+
+ /**
+ * @see IntentFilter#dump(Printer, String)
+ */
+ public void dump(Printer du, String prefix) {
+ mFilter.dump(du, prefix);
+ }
+
+ /**
+ * @see IntentFilter#describeContents()
+ */
+ public final int describeContents() {
+ return mFilter.describeContents();
+ }
+
+ /**
+ * @see IntentFilter#debugCheck()
+ */
+ public boolean debugCheck() {
+ return mFilter.debugCheck();
+ }
+
+ /**
+ * @see IntentFilter#getHostsList()
+ */
+ public ArrayList<String> getHostsList() {
+ return mFilter.getHostsList();
+ }
+
+ /**
+ * @see IntentFilter#getHosts()
+ */
+ public String[] getHosts() {
+ return mFilter.getHosts();
+ }
+
+ /**
+ * Convert a list of {@link IntentFilter} into a list of {@link WatchedIntentFilter}
+ */
+ public static List<WatchedIntentFilter> toWatchedIntentFilterList(List<IntentFilter> inList) {
+ ArrayList<WatchedIntentFilter> outList = new ArrayList<>();
+ for (int i = 0; i < inList.size(); i++) {
+ outList.add(new WatchedIntentFilter(inList.get(i)));
+ }
+ return outList;
+ }
+
+ /**
+ * Convert a list of {@link IntentFilter} into a list of {@link WatchedIntentFilter}
+ */
+ public static List<IntentFilter> toIntentFilterList(List<WatchedIntentFilter> inList) {
+ ArrayList<IntentFilter> outList = new ArrayList<>();
+ for (int i = 0; i < inList.size(); i++) {
+ outList.add(inList.get(i).getIntentFilter());
+ }
+ return outList;
+ }
+
+ /**
+ * Create a snapshot by cloning the object.
+ */
+ public WatchedIntentFilter snapshot() {
+ return new WatchedIntentFilter(this);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index bf2b3c7..a8a6a72 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -24,6 +24,7 @@
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.os.Build;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Patterns;
@@ -32,7 +33,6 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.List;
-import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -251,6 +251,10 @@
* improve the reliability of any legacy verifiers.
*/
private boolean isValidHost(String host) {
+ if (TextUtils.isEmpty(host)) {
+ return false;
+ }
+
mDomainMatcher.reset(host);
return mDomainMatcher.matches();
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
index 2a17c6d..3f00a9d 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
@@ -29,6 +29,7 @@
import android.os.ServiceSpecificException;
import java.util.List;
+import java.util.Objects;
import java.util.UUID;
public class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
@@ -110,6 +111,7 @@
public List<DomainOwner> getOwnersForDomain(@NonNull String domain,
@UserIdInt int userId) {
try {
+ Objects.requireNonNull(domain);
return mService.getOwnersForDomain(domain, userId);
} catch (Exception e) {
throw rethrow(e);
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 4ae79a2..f0fdad0 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -742,6 +742,7 @@
}
public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
+ Objects.requireNonNull(domain);
mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
userId);
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
index 44ff3eb..246810f 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
@@ -22,6 +22,8 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.text.TextUtils;
+import android.util.Patterns;
import com.android.internal.util.CollectionUtils;
import com.android.server.compat.PlatformCompat;
@@ -29,9 +31,13 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.Set;
+import java.util.regex.Matcher;
public final class DomainVerificationUtils {
+ private static final ThreadLocal<Matcher> sCachedMatcher = ThreadLocal.withInitial(
+ () -> Patterns.DOMAIN_NAME.matcher(""));
+
/**
* Consolidates package exception messages. A generic unavailable message is included since the
* caller doesn't bother to check why the package isn't available.
@@ -48,6 +54,15 @@
return false;
}
+ String host = intent.getData().getHost();
+ if (TextUtils.isEmpty(host)) {
+ return false;
+ }
+
+ if (!sCachedMatcher.get().reset(host).matches()) {
+ return false;
+ }
+
Set<String> categories = intent.getCategories();
int categoriesSize = CollectionUtils.size(categories);
if (categoriesSize > 2) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5b333e1..29496b3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4492,8 +4492,8 @@
}
@Override
- public boolean okToAnimate() {
- return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep;
+ public boolean okToAnimate(boolean ignoreScreenOn) {
+ return (ignoreScreenOn || mDefaultDisplayPolicy.isAwake()) && !mDeviceGoingToSleep;
}
/** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d512edf..78b03b2 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -897,12 +897,13 @@
public boolean isScreenOn();
/**
+ * @param ignoreScreenOn {@code true} if screen state should be ignored.
* @return whether the device is currently allowed to animate.
*
* Note: this can be true even if it is not appropriate to animate for reasons that are outside
* of the policy's authority.
*/
- boolean okToAnimate();
+ boolean okToAnimate(boolean ignoreScreenOn);
/**
* Tell the policy that the lid switch has changed state.
diff --git a/services/core/java/com/android/server/power/FaceDownDetector.java b/services/core/java/com/android/server/power/FaceDownDetector.java
index 474ce59..816c81d 100644
--- a/services/core/java/com/android/server/power/FaceDownDetector.java
+++ b/services/core/java/com/android/server/power/FaceDownDetector.java
@@ -330,7 +330,9 @@
private boolean isEnabled() {
return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_FEATURE_ENABLED,
- DEFAULT_FEATURE_ENABLED);
+ DEFAULT_FEATURE_ENABLED)
+ && mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_flipToScreenOffEnabled);
}
private float getAccelerationThreshold() {
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 6ea030f..81a51e2 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -25,6 +25,8 @@
import static android.os.RecoverySystem.ResumeOnRebootRebootErrorCode;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+
import android.annotation.IntDef;
import android.content.Context;
import android.content.IntentSender;
@@ -47,6 +49,7 @@
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.FastImmutableArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -143,7 +146,7 @@
*/
@IntDef({ ROR_NEED_PREPARATION,
ROR_SKIP_PREPARATION_AND_NOTIFY,
- ROR_SKIP_PREPARATION_NOT_NOTIFY})
+ ROR_SKIP_PREPARATION_NOT_NOTIFY })
private @interface ResumeOnRebootActionsOnRequest {}
/**
@@ -151,10 +154,43 @@
*/
@IntDef({ ROR_NOT_REQUESTED,
ROR_REQUESTED_NEED_CLEAR,
- ROR_REQUESTED_SKIP_CLEAR})
+ ROR_REQUESTED_SKIP_CLEAR })
private @interface ResumeOnRebootActionsOnClear {}
/**
+ * Fatal arm escrow errors from lock settings that means the RoR is in a bad state. So clients
+ * need to prepare RoR again.
+ */
+ static final FastImmutableArraySet<Integer> FATAL_ARM_ESCROW_ERRORS =
+ new FastImmutableArraySet<>(new Integer[]{
+ LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY,
+ LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER,
+ LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH,
+ LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY,
+ LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE,
+ });
+
+ /**
+ * The error details for ArmRebootEscrow. It contains error codes from RecoverySystemService
+ * and LockSettingsService.
+ */
+ static class RebootPreparationError {
+ final @ResumeOnRebootRebootErrorCode int mRebootErrorCode;
+ final int mProviderErrorCode; // The supplemental error code from lock settings
+
+ RebootPreparationError(int rebootErrorCode, int providerErrorCode) {
+ mRebootErrorCode = rebootErrorCode;
+ mProviderErrorCode = providerErrorCode;
+ }
+
+ int getErrorCodeForMetrics() {
+ // The ResumeOnRebootRebootErrorCode are aligned with 1000; so it's safe to add them
+ // for metrics purpose.
+ return mRebootErrorCode + mProviderErrorCode;
+ }
+ }
+
+ /**
* Manages shared preference, i.e. the storage used for metrics reporting.
*/
public static class PreferencesManager {
@@ -709,34 +745,40 @@
return true;
}
- private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName,
+ private RebootPreparationError armRebootEscrow(String packageName,
boolean slotSwitch) {
if (packageName == null) {
Slog.w(TAG, "Missing packageName when rebooting with lskf.");
- return RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME;
+ return new RebootPreparationError(
+ RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME, ARM_REBOOT_ERROR_NONE);
}
if (!isLskfCaptured(packageName)) {
- return RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED;
+ return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED,
+ ARM_REBOOT_ERROR_NONE);
}
if (!verifySlotForNextBoot(slotSwitch)) {
- return RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH;
+ return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH,
+ ARM_REBOOT_ERROR_NONE);
}
final long origId = Binder.clearCallingIdentity();
- boolean result;
+ int providerErrorCode;
try {
- result = mInjector.getLockSettingsService().armRebootEscrow();
+ providerErrorCode = mInjector.getLockSettingsService().armRebootEscrow();
} finally {
Binder.restoreCallingIdentity(origId);
}
- if (!result) {
- Slog.w(TAG, "Failure to escrow key for reboot");
- return RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE;
+ if (providerErrorCode != ARM_REBOOT_ERROR_NONE) {
+ Slog.w(TAG, "Failure to escrow key for reboot, providerErrorCode: "
+ + providerErrorCode);
+ return new RebootPreparationError(
+ RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE, providerErrorCode);
}
- return RESUME_ON_REBOOT_REBOOT_ERROR_NONE;
+ return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_NONE,
+ ARM_REBOOT_ERROR_NONE);
}
private boolean useServerBasedRoR() {
@@ -750,7 +792,7 @@
}
private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch,
- @ResumeOnRebootRebootErrorCode int errorCode) {
+ RebootPreparationError escrowError) {
int uid = mInjector.getUidFromPackageName(packageName);
boolean serverBased = useServerBasedRoR();
int preparedClientCount;
@@ -773,15 +815,31 @@
+ " request count %d, lskf captured count %d, duration since lskf captured"
+ " %d seconds.", packageName, preparedClientCount, requestCount,
lskfCapturedCount, durationSeconds));
- mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
- requestCount, slotSwitch, serverBased, durationSeconds, lskfCapturedCount);
+ mInjector.reportRebootEscrowRebootMetrics(escrowError.getErrorCodeForMetrics(), uid,
+ preparedClientCount, requestCount, slotSwitch, serverBased, durationSeconds,
+ lskfCapturedCount);
+ }
+
+ private void clearRoRPreparationStateOnRebootFailure(RebootPreparationError escrowError) {
+ if (!FATAL_ARM_ESCROW_ERRORS.contains(escrowError.mProviderErrorCode)) {
+ return;
+ }
+
+ Slog.w(TAG, "Clearing resume on reboot states for all clients on arm escrow error: "
+ + escrowError.mProviderErrorCode);
+ synchronized (this) {
+ mCallerPendingRequest.clear();
+ mCallerPreparedForReboot.clear();
+ }
}
private @ResumeOnRebootRebootErrorCode int rebootWithLskfImpl(String packageName, String reason,
boolean slotSwitch) {
- @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch);
- reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode);
+ RebootPreparationError escrowError = armRebootEscrow(packageName, slotSwitch);
+ reportMetricsOnRebootWithLskf(packageName, slotSwitch, escrowError);
+ clearRoRPreparationStateOnRebootFailure(escrowError);
+ @ResumeOnRebootRebootErrorCode int errorCode = escrowError.mRebootErrorCode;
if (errorCode != RESUME_ON_REBOOT_REBOOT_ERROR_NONE) {
return errorCode;
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 4adcfb6..9e19f57 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -613,9 +613,11 @@
PackageInstaller.SessionInfo session = mContext.getPackageManager()
.getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
if (session == null || session.isStagedSessionFailed()) {
- iter.remove();
- deleteRollback(rollback,
- "Session " + rollback.getStagedSessionId() + " not existed or failed");
+ if (rollback.isEnabling()) {
+ iter.remove();
+ deleteRollback(rollback, "Session " + rollback.getStagedSessionId()
+ + " not existed or failed");
+ }
continue;
}
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 4f5e8fa..072cc16f 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -16,26 +16,22 @@
package com.android.server.timedetector;
-import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
-import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
-import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
-
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.os.Build;
+import android.database.ContentObserver;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;
-import com.android.internal.R;
-import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
import java.time.Instant;
import java.util.Objects;
@@ -43,62 +39,71 @@
/**
* The real implementation of {@link TimeDetectorStrategyImpl.Environment} used on device.
*/
-public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
+final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
- private static final String TAG = TimeDetectorService.TAG;
-
- private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
-
- /**
- * Time in the past. If automatic time suggestion is before this point, it's
- * incorrect for sure.
- */
- private static final Instant TIME_LOWER_BOUND = Instant.ofEpochMilli(
- Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
-
- /**
- * By default telephony and network only suggestions are accepted and telephony takes
- * precedence over network.
- */
- private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES =
- { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
-
- /**
- * If a newly calculated system clock time and the current system clock time differs by this or
- * more the system clock will actually be updated. Used to prevent the system clock being set
- * for only minor differences.
- */
- private final int mSystemClockUpdateThresholdMillis;
+ private static final String LOG_TAG = TimeDetectorService.TAG;
@NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final ContentResolver mContentResolver;
@NonNull private final PowerManager.WakeLock mWakeLock;
@NonNull private final AlarmManager mAlarmManager;
@NonNull private final UserManager mUserManager;
- @NonNull private final int[] mOriginPriorities;
- public EnvironmentImpl(@NonNull Context context) {
+ // @NonNull after setConfigChangeListener() is called.
+ @GuardedBy("this")
+ private ConfigurationChangeListener mConfigChangeListener;
+
+ EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor) {
mContext = Objects.requireNonNull(context);
mContentResolver = Objects.requireNonNull(context.getContentResolver());
+ mHandler = Objects.requireNonNull(handler);
+ mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
PowerManager powerManager = context.getSystemService(PowerManager.class);
mWakeLock = Objects.requireNonNull(
- powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG));
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG));
mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));
mUserManager = Objects.requireNonNull(context.getSystemService(UserManager.class));
- mSystemClockUpdateThresholdMillis =
- SystemProperties.getInt("ro.sys.time_detector_update_diff",
- SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+ // Wire up the config change listeners. All invocations are performed on the mHandler
+ // thread.
- mOriginPriorities = getOriginPriorities(context);
+ ContentResolver contentResolver = context.getContentResolver();
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ handleAutoTimeDetectionChangedOnHandlerThread();
+ }
+ });
+ }
+
+ /** Internal method for handling the auto time setting being changed. */
+ private void handleAutoTimeDetectionChangedOnHandlerThread() {
+ synchronized (this) {
+ if (mConfigChangeListener == null) {
+ Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
+ }
+ mConfigChangeListener.onChange();
+ }
+ }
+
+ @Override
+ public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
+ synchronized (this) {
+ mConfigChangeListener = Objects.requireNonNull(listener);
+ }
}
@Override
public int systemClockUpdateThresholdMillis() {
- return mSystemClockUpdateThresholdMillis;
+ return mServiceConfigAccessor.systemClockUpdateThresholdMillis();
}
@Override
@@ -112,12 +117,12 @@
@Override
public Instant autoTimeLowerBound() {
- return TIME_LOWER_BOUND;
+ return mServiceConfigAccessor.autoTimeLowerBound();
}
@Override
public int[] autoOriginPriorities() {
- return mOriginPriorities;
+ return mServiceConfigAccessor.getOriginPriorities();
}
@Override
@@ -131,7 +136,7 @@
@Override
public void acquireWakeLock() {
if (mWakeLock.isHeld()) {
- Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
+ Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " already held");
}
mWakeLock.acquire();
}
@@ -160,7 +165,7 @@
private void checkWakeLockHeld() {
if (!mWakeLock.isHeld()) {
- Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held");
+ Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " not held");
}
}
@@ -168,20 +173,4 @@
UserHandle userHandle = UserHandle.of(userId);
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
}
-
- private static int[] getOriginPriorities(@NonNull Context context) {
- String[] originStrings =
- context.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
- if (originStrings.length == 0) {
- return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
- } else {
- int[] origins = new int[originStrings.length];
- for (int i = 0; i < originStrings.length; i++) {
- int origin = stringToOrigin(originStrings[i]);
- origins[i] = origin;
- }
-
- return origins;
- }
- }
}
diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java
new file mode 100644
index 0000000..be4432a
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java
@@ -0,0 +1,141 @@
+/*
+ * 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.timedetector;
+
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
+import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
+
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A singleton that provides access to service configuration for time detection. This hides how
+ * configuration is split between static, compile-time config and dynamic, server-pushed flags. It
+ * provides a rudimentary mechanism to signal when values have changed.
+ */
+final class ServiceConfigAccessor {
+
+ private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
+
+ /**
+ * By default telephony and network only suggestions are accepted and telephony takes
+ * precedence over network.
+ */
+ private static final @TimeDetectorStrategy.Origin int[]
+ DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+
+ /**
+ * Time in the past. If an automatic time suggestion is before this point, it is sure to be
+ * incorrect.
+ */
+ private static final Instant TIME_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli(
+ Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));
+
+ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
+ new ArraySet<>(new String[] {
+ }));
+
+ private static final Object SLOCK = new Object();
+
+ /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
+ @GuardedBy("SLOCK")
+ @Nullable
+ private static ServiceConfigAccessor sInstance;
+
+ @NonNull private final Context mContext;
+ @NonNull private final ServerFlags mServerFlags;
+ @NonNull private final int[] mOriginPriorities;
+
+ /**
+ * If a newly calculated system clock time and the current system clock time differs by this or
+ * more the system clock will actually be updated. Used to prevent the system clock being set
+ * for only minor differences.
+ */
+ private final int mSystemClockUpdateThresholdMillis;
+
+ private ServiceConfigAccessor(@NonNull Context context) {
+ mContext = Objects.requireNonNull(context);
+ mServerFlags = ServerFlags.getInstance(mContext);
+ mOriginPriorities = getOriginPrioritiesInternal();
+ mSystemClockUpdateThresholdMillis =
+ SystemProperties.getInt("ro.sys.time_detector_update_diff",
+ SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+ }
+
+ /** Returns the singleton instance. */
+ static ServiceConfigAccessor getInstance(Context context) {
+ synchronized (SLOCK) {
+ if (sInstance == null) {
+ sInstance = new ServiceConfigAccessor(context);
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Adds a listener that will be called when server flags related to this class change. The
+ * callbacks are delivered on the main looper thread.
+ *
+ * <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
+ * method.
+ */
+ void addListener(@NonNull ConfigurationChangeListener listener) {
+ mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH);
+ }
+
+ @NonNull
+ int[] getOriginPriorities() {
+ return mOriginPriorities;
+ }
+
+ int systemClockUpdateThresholdMillis() {
+ return mSystemClockUpdateThresholdMillis;
+ }
+
+ Instant autoTimeLowerBound() {
+ return TIME_LOWER_BOUND_DEFAULT;
+ }
+
+ private int[] getOriginPrioritiesInternal() {
+ String[] originStrings =
+ mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
+ if (originStrings.length == 0) {
+ return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
+ } else {
+ int[] origins = new int[originStrings.length];
+ for (int i = 0; i < originStrings.length; i++) {
+ int origin = stringToOrigin(originStrings[i]);
+ origins[i] = origin;
+ }
+
+ return origins;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 27e2ee5..14cab38 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -27,12 +27,9 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
-import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
-import android.provider.Settings;
import android.util.IndentingPrintWriter;
import com.android.internal.annotations.VisibleForTesting;
@@ -64,7 +61,16 @@
@Override
public void onStart() {
- TimeDetectorService service = TimeDetectorService.create(getContext());
+ Context context = getContext();
+ Handler handler = FgThread.getHandler();
+
+ ServiceConfigAccessor serviceConfigAccessor =
+ ServiceConfigAccessor.getInstance(context);
+ TimeDetectorStrategy timeDetectorStrategy =
+ TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
+
+ TimeDetectorService service =
+ new TimeDetectorService(context, handler, timeDetectorStrategy);
// Publish the binder service so it can be accessed from other (appropriately
// permissioned) processes.
@@ -77,28 +83,6 @@
@NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
@NonNull private final CallerIdentityInjector mCallerIdentityInjector;
- private static TimeDetectorService create(@NonNull Context context) {
- TimeDetectorStrategyImpl.Environment environment = new EnvironmentImpl(context);
- TimeDetectorStrategy timeDetectorStrategy = new TimeDetectorStrategyImpl(environment);
-
- Handler handler = FgThread.getHandler();
- TimeDetectorService timeDetectorService =
- new TimeDetectorService(context, handler, timeDetectorStrategy);
-
- // Wire up event listening.
- ContentResolver contentResolver = context.getContentResolver();
- contentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
- new ContentObserver(handler) {
- @Override
- public void onChange(boolean selfChange) {
- timeDetectorService.handleAutoTimeDetectionChanged();
- }
- });
-
- return timeDetectorService;
- }
-
@VisibleForTesting
public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
@NonNull TimeDetectorStrategy timeDetectorStrategy) {
@@ -136,6 +120,7 @@
@Override
public boolean updateConfiguration(TimeConfiguration timeConfiguration) {
+ enforceManageTimeDetectorPermission();
// TODO(b/172891783) Add actual logic
return false;
}
@@ -185,12 +170,6 @@
mHandler.post(() -> mTimeDetectorStrategy.suggestExternalTime(timeSignal));
}
- /** Internal method for handling the auto time setting being changed. */
- @VisibleForTesting
- public void handleAutoTimeDetectionChanged() {
- mHandler.post(mTimeDetectorStrategy::handleAutoTimeConfigChanged);
- }
-
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
@Nullable String[] args) {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index cde66be..be382f0 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -92,12 +92,6 @@
/** Returns the configuration that controls time detector behaviour for specified user. */
ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
- /**
- * Handles the auto-time configuration changing For example, when the auto-time setting is
- * toggled on or off.
- */
- void handleAutoTimeConfigChanged();
-
// Utility methods below are to be moved to a better home when one becomes more obvious.
/**
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 289d8d6..db8a59e 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -29,6 +29,8 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
+import android.content.Context;
+import android.os.Handler;
import android.os.TimestampedValue;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
@@ -37,6 +39,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.timezonedetector.ArrayMapWithHistory;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ReferenceWithHistory;
import java.time.Instant;
@@ -132,6 +135,12 @@
public interface Environment {
/**
+ * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
+ * changes that could affect time detection. This is invoked during system server setup.
+ */
+ void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);
+
+ /**
* The absolute threshold below which the system clock need not be updated. i.e. if setting
* the system clock would adjust it by less than this (either backwards or forwards) then it
* need not be set.
@@ -178,8 +187,19 @@
void releaseWakeLock();
}
+ static TimeDetectorStrategy create(
+ @NonNull Context context, @NonNull Handler handler,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor) {
+
+ TimeDetectorStrategyImpl.Environment environment =
+ new EnvironmentImpl(context, handler, serviceConfigAccessor);
+ return new TimeDetectorStrategyImpl(environment);
+ }
+
+ @VisibleForTesting
TimeDetectorStrategyImpl(@NonNull Environment environment) {
mEnvironment = Objects.requireNonNull(environment);
+ mEnvironment.setConfigChangeListener(this::handleAutoTimeConfigChanged);
}
@Override
@@ -279,8 +299,7 @@
return mEnvironment.configurationInternal(userId);
}
- @Override
- public synchronized void handleAutoTimeConfigChanged() {
+ private synchronized void handleAutoTimeConfigChanged() {
boolean enabled = mEnvironment.isAutoTimeDetectionEnabled();
// When automatic time detection is enabled we update the system clock instantly if we can.
// Conversely, when automatic time detection is disabled we leave the clock as it is.
diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
index 0e5f3bf..b84f8a8 100644
--- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
@@ -47,7 +47,7 @@
/**
* The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
*/
-public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment {
+final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment {
private static final String LOG_TAG = TimeZoneDetectorService.TAG;
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 50d37f4..dddb11b 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -133,8 +133,8 @@
}
/**
- * Adds a listener that will be called server flags related to this class change. The callbacks
- * are delivered on the main looper thread.
+ * Adds a listener that will be called when server flags related to this class change. The
+ * callbacks are delivered on the main looper thread.
*
* <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
* method.
diff --git a/services/core/java/com/android/server/trust/OWNERS b/services/core/java/com/android/server/trust/OWNERS
index b039c4b..e2c6ce1 100644
--- a/services/core/java/com/android/server/trust/OWNERS
+++ b/services/core/java/com/android/server/trust/OWNERS
@@ -1 +1 @@
-include /core/java/android/app/trust/OWNERS
+include /core/java/android/service/trust/OWNERS
diff --git a/services/core/java/com/android/server/utils/SnapshotCache.java b/services/core/java/com/android/server/utils/SnapshotCache.java
new file mode 100644
index 0000000..f0fb8b2
--- /dev/null
+++ b/services/core/java/com/android/server/utils/SnapshotCache.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * A class that caches snapshots. Instances are instantiated on a {@link Watchable}; when the
+ * {@link Watchable} reports a change, the cache is cleared. The snapshot() method fetches the
+ * cache if it is valid, or rebuilds the cache if it has been cleared.
+ *
+ * The class is abstract; clients must implement the createSnapshot() method.
+ *
+ * @param <T> The type returned by the snapshot() method.
+ */
+public abstract class SnapshotCache<T> extends Watcher{
+
+ /**
+ * Global snapshot cache enable flag. Set to false for testing or debugging.
+ */
+ private static final boolean ENABLED = true;
+
+ // The source object from which snapshots are created. This may be null if createSnapshot()
+ // does not require it.
+ protected final T mSource;
+
+ // The cached snapshot
+ private T mSnapshot = null;
+
+ // True if the snapshot is sealed and may not be modified.
+ private boolean mSealed = false;
+
+ /**
+ * Create a cache with a source object for rebuilding snapshots and a
+ * {@link Watchable} that notifies when the cache is invalid.
+ * @param source Source data for rebuilding snapshots.
+ * @param watchable The object that notifies when the cache is invalid.
+ */
+ public SnapshotCache(@Nullable T source, @NonNull Watchable watchable) {
+ mSource = source;
+ watchable.registerObserver(this);
+ }
+
+ /**
+ * Notify the object that the source object has changed. If the local object is sealed then
+ * IllegalStateException is thrown. Otherwise, the cache is cleared.
+ */
+ public void onChange(@Nullable Watchable what) {
+ if (mSealed) {
+ throw new IllegalStateException("attempt to change a sealed object");
+ }
+ mSnapshot = null;
+ }
+
+ /**
+ * Seal the cache. Attempts to modify the cache will generate an exception.
+ */
+ public void seal() {
+ mSealed = true;
+ }
+
+ /**
+ * Return a snapshot. This uses the cache if it is non-null. Otherwise it creates a
+ * new snapshot and saves it in the cache.
+ * @return A snapshot as returned by createSnapshot() and possibly cached.
+ */
+ public T snapshot() {
+ T s = mSnapshot;
+ if (s == null || !ENABLED) {
+ s = createSnapshot();
+ mSnapshot = s;
+ }
+ return s;
+ }
+
+ /**
+ * Create a single, uncached snapshot. Clients must implement this per local rules.
+ * @return A snapshot
+ */
+ public abstract T createSnapshot();
+}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index d8a145d9..19fbdbd 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -43,6 +43,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import java.util.Collections;
import java.util.HashMap;
@@ -320,6 +321,17 @@
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
}
+ /** Dumps the state of this snapshot for logging and debugging purposes. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("TelephonySubscriptionSnapshot:");
+ pw.increaseIndent();
+
+ pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap);
+ pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
+
+ pw.decreaseIndent();
+ }
+
@Override
public String toString() {
return "TelephonySubscriptionSnapshot{ "
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index ab9de77..48ccad33 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -31,6 +31,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import java.util.ArrayList;
@@ -118,18 +119,18 @@
if (!mIsQuitting) {
mRouteSelectionCallback = new RouteSelectionCallback();
mConnectivityManager.requestBackgroundNetwork(
- getRouteSelectionRequest(), mHandler, mRouteSelectionCallback);
+ getRouteSelectionRequest(), mRouteSelectionCallback, mHandler);
mWifiBringupCallback = new NetworkBringupCallback();
mConnectivityManager.requestBackgroundNetwork(
- getWifiNetworkRequest(), mHandler, mWifiBringupCallback);
+ getWifiNetworkRequest(), mWifiBringupCallback, mHandler);
for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
final NetworkBringupCallback cb = new NetworkBringupCallback();
mCellBringupCallbacks.add(cb);
mConnectivityManager.requestBackgroundNetwork(
- getCellNetworkRequestForSubId(subId), mHandler, cb);
+ getCellNetworkRequestForSubId(subId), cb, mHandler);
}
} else {
mRouteSelectionCallback = null;
@@ -396,6 +397,18 @@
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
}
+ /** Dumps the state of this record for logging and debugging purposes. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("UnderlyingNetworkRecord:");
+ pw.increaseIndent();
+
+ pw.println("mNetwork: " + network);
+ pw.println("mNetworkCapabilities: " + networkCapabilities);
+ pw.println("mLinkProperties: " + linkProperties);
+
+ pw.decreaseIndent();
+ }
+
/** Builder to incrementally construct an UnderlyingNetworkRecord. */
private static class Builder {
@NonNull private final Network mNetwork;
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 7bc6056..cccb096 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
@@ -26,14 +28,21 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
+import android.net.Uri;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnManager.VcnErrorCode;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -42,9 +51,11 @@
import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
@@ -61,6 +72,11 @@
public class Vcn extends Handler {
private static final String TAG = Vcn.class.getSimpleName();
+ private static final int VCN_LEGACY_SCORE_INT = 52;
+
+ private static final List<Integer> CAPS_REQUIRING_MOBILE_DATA =
+ Arrays.asList(NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN);
+
private static final int MSG_EVENT_BASE = 0;
private static final int MSG_CMD_BASE = 100;
@@ -110,6 +126,15 @@
*/
private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
+ /**
+ * Triggers reevaluation of mobile data enabled conditions.
+ *
+ * <p>Upon this notification, the VCN will check if any of the underlying subIds have mobile
+ * data enabled. If not, the VCN will restart any GatewayConnections providing INTERNET or DUN
+ * with the current mobile data toggle status.
+ */
+ private static final int MSG_EVENT_MOBILE_DATA_TOGGLED = MSG_EVENT_BASE + 5;
+
/** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
@@ -118,6 +143,8 @@
@NonNull private final Dependencies mDeps;
@NonNull private final VcnNetworkRequestListener mRequestListener;
@NonNull private final VcnCallback mVcnCallback;
+ @NonNull private final VcnContentResolver mContentResolver;
+ @NonNull private final ContentObserver mMobileDataSettingsObserver;
/**
* Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs.
@@ -154,6 +181,8 @@
// Accessed from different threads, but always under lock in VcnManagementService
private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
+ private boolean mIsMobileDataEnabled = false;
+
public Vcn(
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@@ -177,10 +206,19 @@
mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback");
mDeps = Objects.requireNonNull(deps, "Missing deps");
mRequestListener = new VcnNetworkRequestListener();
+ mContentResolver = mDeps.newVcnContentResolver(mVcnContext);
+ mMobileDataSettingsObserver = new VcnMobileDataContentObserver(this /* handler */);
+
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
+ mContentResolver.registerContentObserver(
+ uri, true /* notifyForDescendants */, mMobileDataSettingsObserver);
mConfig = Objects.requireNonNull(config, "Missing config");
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
+ // Update mIsMobileDataEnabled before starting handling of NetworkRequests.
+ mIsMobileDataEnabled = getMobileDataStatus();
+
// Register to receive cached and future NetworkRequests
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
}
@@ -230,10 +268,10 @@
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
@Override
- public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
+ public void onNetworkRequested(@NonNull NetworkRequest request) {
Objects.requireNonNull(request, "Missing request");
- sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, score, providerId, request));
+ sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, request));
}
}
@@ -249,7 +287,7 @@
handleConfigUpdated((VcnConfig) msg.obj);
break;
case MSG_EVENT_NETWORK_REQUESTED:
- handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
+ handleNetworkRequested((NetworkRequest) msg.obj);
break;
case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
@@ -260,6 +298,9 @@
case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
handleSafeModeStatusChanged();
break;
+ case MSG_EVENT_MOBILE_DATA_TOGGLED:
+ handleMobileDataToggled();
+ break;
case MSG_CMD_TEARDOWN:
handleTeardown();
break;
@@ -327,25 +368,9 @@
}
}
- private void handleNetworkRequested(
- @NonNull NetworkRequest request, int score, int providerId) {
+ private void handleNetworkRequested(@NonNull NetworkRequest request) {
Slog.v(getLogTag(), "Received request " + request);
- if (score > getNetworkScore()) {
- if (VDBG) {
- Slog.v(
- getLogTag(),
- "Request already satisfied by higher-scoring ("
- + score
- + ") network from "
- + "provider "
- + providerId
- + ": "
- + request);
- }
- return;
- }
-
// If preexisting VcnGatewayConnection(s) satisfy request, return
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
@@ -366,18 +391,37 @@
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request);
+ if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) {
+ // Skip; this network does not provide any services if mobile data is disabled.
+ continue;
+ }
+
final VcnGatewayConnection vcnGatewayConnection =
mDeps.newVcnGatewayConnection(
mVcnContext,
mSubscriptionGroup,
mLastSnapshot,
gatewayConnectionConfig,
- new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
+ new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig),
+ mIsMobileDataEnabled);
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
}
}
}
+ private Set<Integer> getExposedCapabilitiesForMobileDataState(
+ VcnGatewayConnectionConfig gatewayConnectionConfig) {
+ if (mIsMobileDataEnabled) {
+ return gatewayConnectionConfig.getAllExposedCapabilities();
+ }
+
+ final Set<Integer> exposedCapsWithoutMobileData =
+ new ArraySet<>(gatewayConnectionConfig.getAllExposedCapabilities());
+ exposedCapsWithoutMobileData.removeAll(CAPS_REQUIRING_MOBILE_DATA);
+
+ return exposedCapsWithoutMobileData;
+ }
+
private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
mVcnGatewayConnections.remove(config);
@@ -396,12 +440,55 @@
}
}
+ private void handleMobileDataToggled() {
+ final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled;
+ mIsMobileDataEnabled = getMobileDataStatus();
+
+ if (oldMobileDataEnabledStatus != mIsMobileDataEnabled) {
+ // Teardown any GatewayConnections that advertise INTERNET or DUN. If they provide other
+ // services, the VcnGatewayConnections will be restarted without advertising INTERNET or
+ // DUN.
+ for (Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
+ mVcnGatewayConnections.entrySet()) {
+ final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
+ final VcnGatewayConnection gatewayConnection = entry.getValue();
+
+ final Set<Integer> exposedCaps =
+ gatewayConnectionConfig.getAllExposedCapabilities();
+ if (exposedCaps.contains(NET_CAPABILITY_INTERNET)
+ || exposedCaps.contains(NET_CAPABILITY_DUN)) {
+ if (gatewayConnection == null) {
+ Slog.wtf(
+ getLogTag(),
+ "Found gatewayConnectionConfig without GatewayConnection");
+ } else {
+ // TODO(b/184868850): Optimize by restarting NetworkAgents without teardown.
+ gatewayConnection.teardownAsynchronously();
+ }
+ }
+ }
+ }
+ }
+
+ private boolean getMobileDataStatus() {
+ final TelephonyManager genericTelMan =
+ mVcnContext.getContext().getSystemService(TelephonyManager.class);
+
+ for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
+ if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private boolean isRequestSatisfiedByGatewayConnectionConfig(
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
builder.addTransportType(TRANSPORT_CELLULAR);
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- for (int cap : config.getAllExposedCapabilities()) {
+ for (int cap : getExposedCapabilitiesForMobileDataState(config)) {
builder.addCapability(cap);
}
@@ -432,12 +519,20 @@
pw.decreaseIndent();
}
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public boolean isMobileDataEnabled() {
+ return mIsMobileDataEnabled;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public void setMobileDataEnabled(boolean isMobileDataEnabled) {
+ mIsMobileDataEnabled = isMobileDataEnabled;
+ }
+
/** Retrieves the network score for a VCN Network */
- // Package visibility for use in VcnGatewayConnection
- static int getNetworkScore() {
- // TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in
- // subGrp" value
- return 52;
+ // Package visibility for use in VcnGatewayConnection and VcnNetworkProvider
+ static NetworkScore getNetworkScore() {
+ return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build();
}
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
@@ -485,6 +580,17 @@
}
}
+ private class VcnMobileDataContentObserver extends ContentObserver {
+ private VcnMobileDataContentObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED));
+ }
+ }
+
/** External dependencies used by Vcn, for injection in tests */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Dependencies {
@@ -494,13 +600,36 @@
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
VcnGatewayConnectionConfig connectionConfig,
- VcnGatewayStatusCallback gatewayStatusCallback) {
+ VcnGatewayStatusCallback gatewayStatusCallback,
+ boolean isMobileDataEnabled) {
return new VcnGatewayConnection(
vcnContext,
subscriptionGroup,
snapshot,
connectionConfig,
- gatewayStatusCallback);
+ gatewayStatusCallback,
+ isMobileDataEnabled);
+ }
+
+ /** Builds a new VcnContentResolver instance */
+ public VcnContentResolver newVcnContentResolver(VcnContext vcnContext) {
+ return new VcnContentResolver(vcnContext);
+ }
+ }
+
+ /** Proxy Implementation of NetworkAgent, used for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class VcnContentResolver {
+ private final ContentResolver mImpl;
+
+ public VcnContentResolver(VcnContext vcnContext) {
+ mImpl = vcnContext.getContext().getContentResolver();
+ }
+
+ /** Registers the content observer */
+ public void registerContentObserver(
+ @NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer) {
+ mImpl.registerContentObserver(uri, notifyForDescendants, observer);
}
}
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 1d55ba4..23fb95b 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
@@ -47,6 +49,7 @@
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
+import android.net.NetworkScore;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri;
@@ -517,6 +520,7 @@
@NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
@NonNull private final Dependencies mDeps;
@NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
+ private final boolean mIsMobileDataEnabled;
@NonNull private final IpSecManager mIpSecManager;
@@ -626,13 +630,15 @@
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
@NonNull VcnGatewayConnectionConfig connectionConfig,
- @NonNull VcnGatewayStatusCallback gatewayStatusCallback) {
+ @NonNull VcnGatewayStatusCallback gatewayStatusCallback,
+ boolean isMobileDataEnabled) {
this(
vcnContext,
subscriptionGroup,
snapshot,
connectionConfig,
gatewayStatusCallback,
+ isMobileDataEnabled,
new Dependencies());
}
@@ -643,6 +649,7 @@
@NonNull TelephonySubscriptionSnapshot snapshot,
@NonNull VcnGatewayConnectionConfig connectionConfig,
@NonNull VcnGatewayStatusCallback gatewayStatusCallback,
+ boolean isMobileDataEnabled,
@NonNull Dependencies deps) {
super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
mVcnContext = vcnContext;
@@ -650,6 +657,7 @@
mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
mGatewayStatusCallback =
Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback");
+ mIsMobileDataEnabled = isMobileDataEnabled;
mDeps = Objects.requireNonNull(deps, "Missing deps");
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
@@ -1502,7 +1510,7 @@
@NonNull VcnNetworkAgent agent,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
- buildNetworkCapabilities(mConnectionConfig, mUnderlying);
+ buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
final LinkProperties lp =
buildConnectedLinkProperties(
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
@@ -1515,7 +1523,7 @@
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
- buildNetworkCapabilities(mConnectionConfig, mUnderlying);
+ buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
final LinkProperties lp =
buildConnectedLinkProperties(
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
@@ -1843,7 +1851,8 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
static NetworkCapabilities buildNetworkCapabilities(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
- @Nullable UnderlyingNetworkRecord underlying) {
+ @Nullable UnderlyingNetworkRecord underlying,
+ boolean isMobileDataEnabled) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
builder.addTransportType(TRANSPORT_CELLULAR);
@@ -1853,6 +1862,12 @@
// Add exposed capabilities
for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) {
+ // Skip adding INTERNET or DUN if mobile data is disabled.
+ if (!isMobileDataEnabled
+ && (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN)) {
+ continue;
+ }
+
builder.addCapability(cap);
}
@@ -2040,6 +2055,12 @@
"mNetworkAgent.getNetwork(): "
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
+ pw.println("mUnderlying:");
+ pw.increaseIndent();
+ mUnderlying.dump(pw);
+ pw.decreaseIndent();
+ pw.println();
+
pw.decreaseIndent();
}
@@ -2183,7 +2204,7 @@
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@NonNull LinkProperties lp,
- @NonNull int score,
+ @NonNull NetworkScore score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
@@ -2324,7 +2345,7 @@
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@NonNull LinkProperties lp,
- @NonNull int score,
+ @NonNull NetworkScore score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index be0deb5..72cd788 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -16,14 +16,25 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -33,6 +44,7 @@
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
/**
* VCN Network Provider routes NetworkRequests to listeners to bring up tunnels as needed.
@@ -47,15 +59,70 @@
private final Set<NetworkRequestListener> mListeners = new ArraySet<>();
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Dependencies mDeps;
+
/**
- * Cache of NetworkRequest(s), scores and network providers, keyed by NetworkRequest
+ * Cache of NetworkRequest(s).
*
* <p>NetworkRequests are immutable once created, and therefore can be used as stable keys.
*/
- private final ArrayMap<NetworkRequest, NetworkRequestEntry> mRequests = new ArrayMap<>();
+ private final Set<NetworkRequest> mRequests = new ArraySet<>();
- public VcnNetworkProvider(Context context, Looper looper) {
- super(context, looper, VcnNetworkProvider.class.getSimpleName());
+ public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) {
+ this(context, looper, new Dependencies());
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public VcnNetworkProvider(
+ @NonNull Context context, @NonNull Looper looper, @NonNull Dependencies dependencies) {
+ super(
+ Objects.requireNonNull(context, "Missing context"),
+ Objects.requireNonNull(looper, "Missing looper"),
+ TAG);
+
+ mContext = context;
+ mHandler = new Handler(looper);
+ mDeps = Objects.requireNonNull(dependencies, "Missing dependencies");
+ }
+
+ /** Registers this VcnNetworkProvider and a generic network offer with ConnectivityService. */
+ public void register() {
+ mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(this);
+ mDeps.registerNetworkOffer(
+ this,
+ Vcn.getNetworkScore(), // score filter
+ buildCapabilityFilter(),
+ new HandlerExecutor(mHandler),
+ new NetworkOfferCallback() {
+ @Override
+ public void onNetworkNeeded(@NonNull NetworkRequest request) {
+ handleNetworkRequested(request);
+ }
+
+ @Override
+ public void onNetworkUnneeded(@NonNull NetworkRequest request) {
+ handleNetworkRequestWithdrawn(request);
+ }
+ });
+ }
+
+ /** Builds the filter for NetworkRequests that can be served by the VcnNetworkProvider. */
+ private NetworkCapabilities buildCapabilityFilter() {
+ final NetworkCapabilities.Builder builder =
+ new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_TRUSTED)
+ .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NET_CAPABILITY_NOT_VPN)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ for (int cap : VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES) {
+ builder.addCapability(cap);
+ }
+
+ return builder.build();
}
/**
@@ -80,77 +147,37 @@
/** Sends all cached NetworkRequest(s) to the specified listener. */
@VisibleForTesting(visibility = Visibility.PACKAGE)
public void resendAllRequests(@NonNull NetworkRequestListener listener) {
- for (NetworkRequestEntry entry : mRequests.values()) {
- notifyListenerForEvent(listener, entry);
+ for (NetworkRequest request : mRequests) {
+ notifyListenerForEvent(listener, request);
}
}
private void notifyListenerForEvent(
- @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
- listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);
+ @NonNull NetworkRequestListener listener, @NonNull NetworkRequest request) {
+ listener.onNetworkRequested(request);
}
- @Override
- public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
+ private void handleNetworkRequested(@NonNull NetworkRequest request) {
if (VDBG) {
- Slog.v(
- TAG,
- "Network requested: Request = "
- + request
- + ", score = "
- + score
- + ", providerId = "
- + providerId);
+ Slog.v(TAG, "Network requested: Request = " + request);
}
- final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId);
-
- // NetworkRequests are immutable once created, and therefore can be used as stable keys.
- mRequests.put(request, entry);
+ mRequests.add(request);
// TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on
// Default Data Sub, or similar)
for (NetworkRequestListener listener : mListeners) {
- notifyListenerForEvent(listener, entry);
+ notifyListenerForEvent(listener, request);
}
}
- @Override
- public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
+ private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
mRequests.remove(request);
}
- private static class NetworkRequestEntry {
- public final NetworkRequest mRequest;
- public final int mScore;
- public final int mProviderId;
-
- private NetworkRequestEntry(@NonNull NetworkRequest request, int score, int providerId) {
- mRequest = Objects.requireNonNull(request, "Missing request");
- mScore = score;
- mProviderId = providerId;
- }
-
- /**
- * Dumps the state of this NetworkRequestEntry for logging and debugging purposes.
- *
- * <p>PII and credentials MUST NEVER be dumped here.
- */
- public void dump(IndentingPrintWriter pw) {
- pw.println("NetworkRequestEntry:");
- pw.increaseIndent();
-
- pw.println("mRequest: " + mRequest);
- pw.println("mScore: " + mScore);
- pw.println("mProviderId: " + mProviderId);
-
- pw.decreaseIndent();
- }
- }
-
// package-private
interface NetworkRequestListener {
- void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId);
+ void onNetworkRequested(@NonNull NetworkRequest request);
}
/**
@@ -163,17 +190,35 @@
pw.increaseIndent();
pw.println("mListeners:");
+ pw.increaseIndent();
for (NetworkRequestListener listener : mListeners) {
pw.println(listener);
}
+ pw.decreaseIndent();
pw.println();
- pw.println("mRequests.values:");
- for (NetworkRequestEntry entry : mRequests.values()) {
- entry.dump(pw);
+ pw.println("mRequests:");
+ pw.increaseIndent();
+ for (NetworkRequest request : mRequests) {
+ pw.println(request);
}
+ pw.decreaseIndent();
pw.println();
pw.decreaseIndent();
}
+
+ /** Proxy class for dependencies used for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class Dependencies {
+ /** Registers a given network offer for the given provider. */
+ public void registerNetworkOffer(
+ @NonNull VcnNetworkProvider provider,
+ @NonNull NetworkScore score,
+ @NonNull NetworkCapabilities capabilitiesFilter,
+ @NonNull Executor executor,
+ @NonNull NetworkOfferCallback callback) {
+ provider.registerNetworkOffer(score, capabilitiesFilter, executor, callback);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/vcn/util/MtuUtils.java b/services/core/java/com/android/server/vcn/util/MtuUtils.java
index 49c1a02..5d40cca 100644
--- a/services/core/java/com/android/server/vcn/util/MtuUtils.java
+++ b/services/core/java/com/android/server/vcn/util/MtuUtils.java
@@ -113,7 +113,6 @@
return IPV6_MIN_MTU;
}
- boolean hasUnknownAlgorithm = false;
int maxAuthOverhead = 0;
int maxCryptOverhead = 0;
int maxAuthCryptOverhead = 0;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5b4e6a0..6d72999 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -587,7 +587,14 @@
AnimatingActivityRegistry mAnimatingActivityRegistry;
- private Task mLastParent;
+ // Set whenever the ActivityRecord gets reparented to a Task so we can know the last known
+ // parent was when the ActivityRecord is detached from the hierarchy
+ private Task mLastKnownParent;
+
+ // Set to the previous Task parent of the ActivityRecord when it is reparented to a new Task
+ // due to picture-in-picture. This gets cleared whenever this activity or the Task
+ // it references to gets removed. This should also be cleared when we move out of pip.
+ private Task mLastParentBeforePip;
boolean firstWindowDrawn;
/** Whether the visible window(s) of this activity is drawn. */
@@ -1096,6 +1103,9 @@
pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
}
}
+ if (mLastParentBeforePip != null) {
+ pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId);
+ }
dumpLetterboxInfo(pw, prefix);
}
@@ -1133,6 +1143,8 @@
pw.println(prefix + " letterboxBackgroundWallpaperBlurRadius="
+ getLetterboxWallpaperBlurRadius());
}
+ pw.println(prefix + " letterboxHorizontalPositionMultiplier="
+ + mWmService.getLetterboxHorizontalPositionMultiplier());
}
/**
@@ -1349,7 +1361,7 @@
if (getDisplayContent() != null) {
getDisplayContent().mClosingApps.remove(this);
}
- } else if (mLastParent != null && mLastParent.getRootTask() != null) {
+ } else if (mLastKnownParent != null && mLastKnownParent.getRootTask() != null) {
task.getRootTask().mExitingActivities.remove(this);
}
final Task rootTask = getRootTask();
@@ -1362,7 +1374,11 @@
? rootTask.getAnimatingActivityRegistry()
: null;
- mLastParent = task;
+ mLastKnownParent = task;
+ if (mLastKnownParent == mLastParentBeforePip) {
+ // Activity's reparented back from pip, clear the links once established
+ clearLastParentBeforePip();
+ }
updateColorTransform();
@@ -1381,6 +1397,26 @@
}
}
+ /**
+ * Sets {@link #mLastParentBeforePip} to the current parent Task, it's caller's job to ensure
+ * {@link #getTask()} is set before this is called.
+ */
+ void setLastParentBeforePip() {
+ mLastParentBeforePip = getTask();
+ mLastParentBeforePip.mChildPipActivity = this;
+ }
+
+ private void clearLastParentBeforePip() {
+ if (mLastParentBeforePip != null) {
+ mLastParentBeforePip.mChildPipActivity = null;
+ mLastParentBeforePip = null;
+ }
+ }
+
+ @Nullable Task getLastParentBeforePip() {
+ return mLastParentBeforePip;
+ }
+
private void updateColorTransform() {
if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
getPendingTransaction().setColorTransform(mSurfaceControl,
@@ -3434,6 +3470,7 @@
*/
void cleanUp(boolean cleanServices, boolean setState) {
task.cleanUpActivityReferences(this);
+ clearLastParentBeforePip();
deferRelaunchUntilPaused = false;
frozenBeforeDestroy = false;
@@ -4655,7 +4692,8 @@
// still check DC#okToAnimate again if the transition animation is fine to apply.
// TODO(new-app-transition): Rewrite this logic using WM Shell.
final boolean recentsAnimating = isAnimating(PARENTS, ANIMATION_TYPE_RECENTS);
- if (okToAnimate(true /* ignoreFrozen */) && (appTransition.isTransitionSet()
+ if (okToAnimate(true /* ignoreFrozen */, canTurnScreenOn())
+ && (appTransition.isTransitionSet()
|| (recentsAnimating && !isActivityTypeHome()))) {
if (visible) {
displayContent.mOpeningApps.add(this);
@@ -5862,6 +5900,12 @@
nowVisible = true;
lastVisibleTime = SystemClock.uptimeMillis();
mAtmService.scheduleAppGcsLocked();
+ // The nowVisible may be false in onAnimationFinished because the transition animation
+ // was started by starting window but the main window hasn't drawn so the procedure
+ // didn't schedule. Hence also check when nowVisible becomes true (drawn) to avoid the
+ // closing activity having to wait until idle timeout to be stopped or destroyed if the
+ // next activity won't report idle (e.g. repeated view animation).
+ mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
}
}
@@ -6678,26 +6722,26 @@
// traverse the copy.
final ArrayList<WindowState> children = new ArrayList<>(mChildren);
children.forEach(WindowState::onExitAnimationDone);
+ // The starting window could transfer to another activity after app transition started, in
+ // that case the latest top activity might not receive exit animation done callback if the
+ // starting window didn't applied exit animation success. Notify animation finish to the
+ // starting window if needed.
+ if (task != null && startingMoved) {
+ final WindowState transferredStarting = task.getWindow(w ->
+ w.mAttrs.type == TYPE_APPLICATION_STARTING);
+ if (transferredStarting != null && transferredStarting.mAnimatingExit
+ && !transferredStarting.isSelfAnimating(0 /* flags */,
+ ANIMATION_TYPE_WINDOW_ANIMATION)) {
+ transferredStarting.onExitAnimationDone();
+ }
+ }
getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
scheduleAnimation();
- if (!mTaskSupervisor.mStoppingActivities.isEmpty()
- || !mTaskSupervisor.mFinishingActivities.isEmpty()) {
- if (mRootWindowContainer.allResumedActivitiesIdle()) {
- // If all activities are already idle then we now need to make sure we perform
- // the full stop of this activity. This is because we won't do that while they
- // are still waiting for the animation to finish.
- mTaskSupervisor.scheduleIdle();
- } else if (mRootWindowContainer.allResumedActivitiesVisible()) {
- // If all resumed activities are already visible (and should be drawn, see
- // updateReportedVisibility ~ nowVisible) but not idle, we still schedule to
- // process the stopping and finishing activities because the transition is done.
- // This also avoids if the next activity never reports idle (e.g. animating view),
- // the previous will need to wait until idle timeout to be stopped or destroyed.
- mTaskSupervisor.scheduleProcessStoppingAndFinishingActivities();
- }
- }
+ // Schedule to handle the stopping and finishing activities which the animation is done
+ // because the activities which were animating have not been stopped yet.
+ mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -7021,11 +7065,13 @@
// and back which can cause visible issues (see b/184078928).
final int parentWindowingMode =
newParentConfiguration.windowConfiguration.getWindowingMode();
+ final boolean isFixedOrientationLetterboxAllowed =
+ isSplitScreenWindowingMode(parentWindowingMode)
+ || parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
+ || parentWindowingMode == WINDOWING_MODE_FULLSCREEN;
// TODO(b/181207944): Consider removing the if condition and always run
// resolveFixedOrientationConfiguration() since this should be applied for all cases.
- if (isSplitScreenWindowingMode(parentWindowingMode)
- || parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
- || parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ if (isFixedOrientationLetterboxAllowed) {
resolveFixedOrientationConfiguration(newParentConfiguration);
}
@@ -7046,12 +7092,16 @@
resolveFullscreenConfiguration(newParentConfiguration);
}
+ if (isFixedOrientationLetterboxAllowed || mCompatDisplayInsets != null
+ // In fullscreen, can be letterboxed for aspect ratio.
+ || !inMultiWindowMode()) {
+ updateResolvedBoundsHorizontalPosition(newParentConfiguration);
+ }
+
if (mVisibleRequested) {
updateCompatDisplayInsets();
}
- // TODO(b/175212232): Consolidate position logic from each "resolve" method above here.
-
// Assign configuration sequence number into hierarchy because there is a different way than
// ensureActivityConfiguration() in this class that uses configuration in WindowState during
// layout traversals.
@@ -7082,6 +7132,47 @@
}
}
+
+ /**
+ * Adjusts horizontal position of resolved bounds if they doesn't fill the parent using gravity
+ * requested in the config or via an ADB command. For more context see {@link
+ * WindowManagerService#getLetterboxHorizontalPositionMultiplier}.
+ */
+ private void updateResolvedBoundsHorizontalPosition(Configuration newParentConfiguration) {
+ final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+ final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+ final Rect screenResolvedBounds =
+ mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
+ final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
+ final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
+ if (resolvedBounds.isEmpty() || parentBounds.width() == screenResolvedBounds.width()) {
+ return;
+ }
+
+ int offsetX = 0;
+ if (screenResolvedBounds.width() >= parentAppBounds.width()) {
+ // If resolved bounds overlap with insets, center within app bounds.
+ offsetX = getHorizontalCenterOffset(
+ parentAppBounds.width(), screenResolvedBounds.width());
+ } else {
+ float positionMultiplier = mWmService.getLetterboxHorizontalPositionMultiplier();
+ positionMultiplier =
+ (positionMultiplier < 0.0f || positionMultiplier > 1.0f)
+ // Default to central position if invalid value is provided.
+ ? 0.5f : positionMultiplier;
+ offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
+ * positionMultiplier);
+ }
+
+ if (mSizeCompatBounds != null) {
+ mSizeCompatBounds.offset(offsetX, 0 /* offsetY */);
+ final int dx = mSizeCompatBounds.left - resolvedBounds.left;
+ offsetBounds(resolvedConfig, dx, 0 /* offsetY */);
+ } else {
+ offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
+ }
+ }
+
/**
* Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
* orientation then aspect ratio restrictions are also already respected.
@@ -7159,7 +7250,10 @@
resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + height);
} else {
final int width = (int) Math.rint(parentHeight / aspect);
- final int left = parentBounds.centerX() - width / 2;
+ 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);
}
@@ -7211,12 +7305,6 @@
task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
getFixedRotationTransformDisplayInfo());
}
- if (needToBeCentered) {
- // Offset to center relative to parent's app bounds.
- final int offsetX = getHorizontalCenterOffset(
- parentAppBounds.width(), resolvedBounds.width());
- offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
- }
}
/**
@@ -7314,8 +7402,8 @@
final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
- // Calculates the scale and offset to horizontal center the size compatibility bounds into
- // the region which is available to application.
+ // Calculates the scale the size compatibility bounds into the region which is available
+ // to application.
final int contentW = resolvedAppBounds.width();
final int contentH = resolvedAppBounds.height();
final int viewportW = containerAppBounds.width();
@@ -7323,8 +7411,9 @@
// Only allow to scale down.
mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
? 1f : Math.min((float) viewportW / contentW, (float) viewportH / contentH);
- final int screenTopInset = containerAppBounds.top - containerBounds.top;
- final boolean topNotAligned = screenTopInset != resolvedAppBounds.top - resolvedBounds.top;
+ final int containerTopInset = containerAppBounds.top - containerBounds.top;
+ final boolean topNotAligned =
+ containerTopInset != resolvedAppBounds.top - resolvedBounds.top;
if (mSizeCompatScale != 1f || topNotAligned) {
if (mSizeCompatBounds == null) {
mSizeCompatBounds = new Rect();
@@ -7333,18 +7422,15 @@
mSizeCompatBounds.offsetTo(0, 0);
mSizeCompatBounds.scale(mSizeCompatScale);
// The insets are included in height, e.g. the area of real cutout shouldn't be scaled.
- mSizeCompatBounds.bottom += screenTopInset;
+ mSizeCompatBounds.bottom += containerTopInset;
} else {
mSizeCompatBounds = null;
}
- // Center horizontally in parent (app bounds) and align to top of parent (bounds)
- // - this is a UX choice.
- final int offsetX = getHorizontalCenterOffset(
- (int) viewportW, (int) (contentW * mSizeCompatScale));
+ // 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 int screenPosX = (fillContainer
- ? containerBounds.left : containerAppBounds.left) + offsetX;
+ final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
final int screenPosY = containerBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
if (mSizeCompatBounds != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 75a188e..1158a9c 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2721,8 +2721,22 @@
launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
break;
case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
- launchFlags &=
- ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
+ if (mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK) {
+ // Remove MULTIPLE_TASK flag along with NEW_DOCUMENT only if NEW_DOCUMENT
+ // is set, otherwise we still want to keep the MULTIPLE_TASK flag (if
+ // any) for singleInstancePerTask that the multiple tasks can be created,
+ // or a singleInstancePerTask activity is basically the same as a
+ // singleTask activity when documentLaunchMode set to never.
+ if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) {
+ launchFlags &= ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+ | FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ } else {
+ // TODO(b/184903976): Should FLAG_ACTIVITY_MULTIPLE_TASK always be
+ // removed for document-never activity?
+ launchFlags &=
+ ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
break;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bdde369..2b1cf39 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2027,7 +2027,9 @@
}
final void scheduleIdle() {
- mHandler.sendEmptyMessage(IDLE_NOW_MSG);
+ if (!mHandler.hasMessages(IDLE_NOW_MSG)) {
+ mHandler.sendEmptyMessage(IDLE_NOW_MSG);
+ }
}
/**
@@ -2115,8 +2117,10 @@
}
}
- void scheduleProcessStoppingAndFinishingActivities() {
- if (!mHandler.hasMessages(PROCESS_STOPPING_AND_FINISHING_MSG)) {
+ void scheduleProcessStoppingAndFinishingActivitiesIfNeeded() {
+ if ((!mStoppingActivities.isEmpty() || !mFinishingActivities.isEmpty())
+ && !mHandler.hasMessages(PROCESS_STOPPING_AND_FINISHING_MSG)
+ && mRootWindowContainer.allResumedActivitiesVisible()) {
mHandler.sendEmptyMessage(PROCESS_STOPPING_AND_FINISHING_MSG);
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 99289e0..394ae7e 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1679,11 +1679,15 @@
|| transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
}
- static boolean isKeyguardTransitOld(@TransitionOldType int transit) {
- return isKeyguardGoingAwayTransitOld(transit) || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+ static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
+ return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
|| transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
+ static boolean isKeyguardTransitOld(@TransitionOldType int transit) {
+ return isKeyguardGoingAwayTransitOld(transit) || isKeyguardOccludeTransitOld(transit);
+ }
+
static boolean isTaskTransitOld(@TransitionOldType int transit) {
return isTaskOpenTransitOld(transit)
|| transit == TRANSIT_OLD_TASK_CLOSE
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 9a43ca8..e7c51a4 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -68,7 +68,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Trace;
import android.util.ArrayMap;
@@ -428,43 +427,37 @@
return mainWindow != null ? mainWindow.mAttrs : null;
}
- RemoteAnimationAdapter getRemoteAnimationOverride(@NonNull WindowContainer container,
+ RemoteAnimationAdapter getRemoteAnimationOverride(@Nullable WindowContainer container,
@TransitionOldType int transit, ArraySet<Integer> activityTypes) {
- final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition();
- if (definition != null) {
- final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
- if (adapter != null) {
- return adapter;
+ if (container != null) {
+ final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition();
+ if (definition != null) {
+ final RemoteAnimationAdapter adapter = definition.getAdapter(transit,
+ activityTypes);
+ if (adapter != null) {
+ return adapter;
+ }
}
}
- if (mRemoteAnimationDefinition != null) {
- final RemoteAnimationAdapter adapter = mRemoteAnimationDefinition.getAdapter(
- transit, activityTypes);
- if (adapter != null) {
- return adapter;
- }
- }
- return null;
+ return mRemoteAnimationDefinition != null
+ ? mRemoteAnimationDefinition.getAdapter(transit, activityTypes)
+ : null;
}
/**
* Overrides the pending transition with the remote animation defined for the transition in the
* set of defined remote animations in the app window token.
*/
- private void overrideWithRemoteAnimationIfSet(ActivityRecord animLpActivity,
+ private void overrideWithRemoteAnimationIfSet(@Nullable ActivityRecord animLpActivity,
@TransitionOldType int transit, ArraySet<Integer> activityTypes) {
if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) {
// The crash transition has higher priority than any involved remote animations.
return;
}
- if (animLpActivity == null) {
- return;
- }
final RemoteAnimationAdapter adapter =
getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
if (adapter != null) {
- animLpActivity.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
- adapter);
+ mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
}
}
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index 128d452..d920267 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -18,24 +18,52 @@
import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.view.ICrossWindowBlurEnabledListener;
import com.android.internal.annotations.GuardedBy;
+/**
+ * Keeps track of the different factors that determine whether cross-window blur is enabled
+ * or disabled. Also keeps a list of all interested listeners and notifies them when the
+ * blur enabled state changes.
+ */
final class BlurController {
-
+ private final PowerManager mPowerManager;
private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
mBlurEnabledListeners = new RemoteCallbackList<>();
+ // We don't use the WM global lock, because the BlurController is not involved in window
+ // drawing and only receives binder calls that don't need synchronization with the rest of WM
private final Object mLock = new Object();
@GuardedBy("mLock")
boolean mBlurEnabled;
@GuardedBy("mLock")
boolean mBlurForceDisabled;
+ @GuardedBy("mLock")
+ boolean mInBatterySaverMode;
- BlurController() {
- mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+ BlurController(Context context, PowerManager powerManager) {
+ mPowerManager = powerManager;
+ mInBatterySaverMode = mPowerManager.isPowerSaveMode();
+ updateBlurEnabledLocked();
+
+ IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ context.registerReceiverForAllUsers(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
+ setBatterySaverEnabled(mPowerManager.isPowerSaveMode());
+ }
+ }
+ }, filter, null, null);
}
boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
@@ -59,8 +87,16 @@
}
+ void setBatterySaverEnabled(boolean enabled) {
+ synchronized (mLock) {
+ mInBatterySaverMode = enabled;
+ updateBlurEnabledLocked();
+ }
+ }
+
private void updateBlurEnabledLocked() {
- final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurForceDisabled;
+ final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurForceDisabled
+ && !mInBatterySaverMode;
if (mBlurEnabled == newEnabled) {
return;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4b735c2..c44f4e3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4436,9 +4436,14 @@
}
boolean okToDisplay(boolean ignoreFrozen) {
+ return okToDisplay(ignoreFrozen, false /* ignoreScreenOn */);
+ }
+
+ boolean okToDisplay(boolean ignoreFrozen, boolean ignoreScreenOn) {
if (mDisplayId == DEFAULT_DISPLAY) {
return (!mWmService.mDisplayFrozen || ignoreFrozen)
- && mWmService.mDisplayEnabled && mWmService.mPolicy.isScreenOn();
+ && mWmService.mDisplayEnabled
+ && (ignoreScreenOn || mWmService.mPolicy.isScreenOn());
}
return mDisplayInfo.state == Display.STATE_ON;
}
@@ -4448,8 +4453,13 @@
}
boolean okToAnimate(boolean ignoreFrozen) {
- return okToDisplay(ignoreFrozen) &&
- (mDisplayId != DEFAULT_DISPLAY || mWmService.mPolicy.okToAnimate());
+ return okToAnimate(ignoreFrozen, false /* ignoreScreenOn */);
+ }
+
+ boolean okToAnimate(boolean ignoreFrozen, boolean ignoreScreenOn) {
+ return okToDisplay(ignoreFrozen, ignoreScreenOn)
+ && (mDisplayId != DEFAULT_DISPLAY
+ || mWmService.mPolicy.okToAnimate(ignoreScreenOn));
}
static final class TaskForResizePointSearchResult {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 9ff701c..e1fc75e 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -731,7 +731,7 @@
private RotationAnimationPair selectRotationAnimation() {
// If the screen is off or non-interactive, force a jumpcut.
final boolean forceJumpcut = !mDisplayPolicy.isScreenOnFully()
- || !mService.mPolicy.okToAnimate();
+ || !mService.mPolicy.okToAnimate(false /* ignoreScreenOn */);
final WindowState topFullscreen = mDisplayPolicy.getTopFullscreenOpaqueWindow();
if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation topFullscreen="
+ topFullscreen + " rotationAnimation="
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 20216c3..8ff9fba 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -341,11 +341,10 @@
/**
* Called when occluded state changed.
*
- * @param currentTaskControllingOcclusion the task that controls the state whether keyguard
- * should be occluded. That is the task to be shown on top of keyguard if it requests so.
+ * @param topActivity the activity that controls the state whether keyguard should
+ * be occluded. That is the activity to be shown on top of keyguard if it requests so.
*/
- private void handleOccludedChanged(
- int displayId, @Nullable Task currentTaskControllingOcclusion) {
+ private void handleOccludedChanged(int displayId, @Nullable ActivityRecord topActivity) {
// TODO(b/113840485): Handle app transition for individual display, and apply occluded
// state change to secondary displays.
// For now, only default display fully supports occluded change. Other displays only
@@ -364,6 +363,13 @@
isDisplayOccluded(DEFAULT_DISPLAY)
? TRANSIT_KEYGUARD_OCCLUDE
: TRANSIT_KEYGUARD_UNOCCLUDE);
+ // When the occluding activity also turns on the display, visibility of the activity
+ // can be committed before KEYGUARD_OCCLUDE transition is handled.
+ // Set mRequestForceTransition flag to make sure that the app transition animation
+ // is applied for such case.
+ if (topActivity != null) {
+ topActivity.mRequestForceTransition = true;
+ }
updateKeyguardSleepToken(DEFAULT_DISPLAY);
mWindowManager.executeAppTransition();
} finally {
@@ -580,7 +586,7 @@
if (lastOccluded != mOccluded) {
occludingChange = true;
- controller.handleOccludedChanged(mDisplayId, task);
+ controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
}
if (occludingChange || turningScreenOn) {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 6631a3e..4bb48b0b 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1415,6 +1415,9 @@
return true;
}
+ // The given task if always treated as in visible range if it is the origin of pinned task.
+ if (task.mChildPipActivity != null) return true;
+
if (mMaxNumVisibleTasks >= 0) {
// Always keep up to the max number of recent tasks, but return false afterwards
return numVisibleTasks <= mMaxNumVisibleTasks;
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index f851e35..67bc7af 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -121,7 +121,10 @@
// Create the app targets
final RemoteAnimationTarget[] appTargets = createAppAnimations();
- if (appTargets.length == 0) {
+ if (appTargets.length == 0 && !AppTransition.isKeyguardOccludeTransitOld(transit)) {
+ // Keyguard occlude transition can be executed before the occluding activity becomes
+ // visible. Even in this case, KeyguardService expects to receive binder call, so we
+ // don't cancel remote animation.
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
"goodToGo(): No apps to animate, mPendingAnimations=%d",
mPendingAnimations.size());
@@ -133,12 +136,16 @@
// Create the remote wallpaper animation targets (if any)
final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
- // TODO(bc-unlock): Create the remote non app animation targets (if any)
+ // Create the remote non app animation targets (if any)
final RemoteAnimationTarget[] nonAppTargets = createNonAppWindowAnimations(transit);
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
try {
linkToDeathOfRunner();
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): onAnimationStart,"
+ + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
+ AppTransition.appTransitionOldToString(transit), appTargets.length,
+ wallpaperTargets.length, nonAppTargets.length);
mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets,
wallpaperTargets, nonAppTargets, mFinishedCallback);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 52551ec..b9fc8b1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2124,6 +2124,8 @@
.setDeferTaskAppear(true)
.setHasBeenVisible(true)
.build();
+ // Establish bi-directional link between the original and pinned task.
+ r.setLastParentBeforePip();
// It's possible the task entering PIP is in freeform, so save the last
// non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
// to its previous freeform bounds.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8690499..07f81c7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -131,6 +131,7 @@
import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
import static com.android.server.wm.TaskProto.DISPLAY_ID;
import static com.android.server.wm.TaskProto.FILLS_PARENT;
+import static com.android.server.wm.TaskProto.HAS_CHILD_PIP_ACTIVITY;
import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS;
import static com.android.server.wm.TaskProto.MIN_HEIGHT;
import static com.android.server.wm.TaskProto.MIN_WIDTH;
@@ -836,6 +837,14 @@
// The task will be removed when TaskOrganizer, which is managing the task, is destroyed.
boolean mRemoveWithTaskOrganizer;
+ /**
+ * Reference to the pinned activity that is logically parented to this task, ie.
+ * the previous top activity within this task is put into pinned mode.
+ * This always gets cleared in pair with the ActivityRecord-to-Task link as seen in
+ * {@link ActivityRecord#clearLastParentBeforePip()}.
+ */
+ ActivityRecord mChildPipActivity;
+
private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -1841,6 +1850,10 @@
/** Completely remove all activities associated with an existing task. */
void performClearTask(String reason) {
+ // The original task is to be removed, try remove also the pinned task.
+ if (mChildPipActivity != null && mChildPipActivity.getTask() != null) {
+ mTaskSupervisor.removeRootTask(mChildPipActivity.getTask());
+ }
// Broken down into to cases to avoid object create due to capturing mStack.
if (getRootTask() == null) {
forAllActivities((r) -> {
@@ -4449,6 +4462,7 @@
}
pw.print(prefix); pw.print("taskId=" + mTaskId);
pw.println(" rootTaskId=" + getRootTaskId());
+ pw.print(prefix); pw.println("hasChildPipActivity=" + (mChildPipActivity != null));
pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible());
pw.print(prefix); pw.print("mResizeMode=");
pw.print(ActivityInfo.resizeModeToString(mResizeMode));
@@ -5328,7 +5342,6 @@
return;
}
final int currentMode = getWindowingMode();
- final int currentOverrideMode = getRequestedOverrideWindowingMode();
final Task topTask = getTopMostTask();
int windowingMode = preferredWindowingMode;
@@ -5397,9 +5410,26 @@
mTaskSupervisor.mNoAnimActivities.add(topActivity);
}
super.setWindowingMode(windowingMode);
- // setWindowingMode triggers an onConfigurationChanged cascade which can result in a
- // different resolved windowing mode (usually when preferredWindowingMode is UNDEFINED).
- windowingMode = getWindowingMode();
+
+ // Try reparent pinned activity back to its original task after onConfigurationChanged
+ // cascade finishes. This is done on Task level instead of
+ // {@link ActivityRecord#onConfigurationChanged(Configuration)} since when we exit PiP,
+ // we set final windowing mode on the ActivityRecord first and then on its Task when
+ // the exit PiP transition finishes. Meanwhile, the exit transition is always
+ // performed on its original task, reparent immediately in ActivityRecord breaks it.
+ if (currentMode == WINDOWING_MODE_PINNED) {
+ if (topActivity != null && topActivity.getLastParentBeforePip() != null) {
+ // Do not reparent if the pinned task is in removal, indicated by the
+ // force hidden flag.
+ if (!isForceHidden()) {
+ final Task lastParentBeforePip = topActivity.getLastParentBeforePip();
+ topActivity.reparent(lastParentBeforePip,
+ lastParentBeforePip.getChildCount() /* top */,
+ "movePinnedActivityToOriginalTask");
+ lastParentBeforePip.moveToFront("movePinnedActivityToOriginalTask");
+ }
+ }
+ }
if (creating) {
// Nothing else to do if we don't have a window container yet. E.g. call from ctor.
@@ -7530,7 +7560,11 @@
final Task task = getBottomMostTask();
setWindowingMode(WINDOWING_MODE_UNDEFINED);
- getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
+ // Task could have been removed from the hierarchy due to windowing mode change
+ // where its only child is reparented back to their original parent task.
+ if (isAttached()) {
+ getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
+ }
mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
});
@@ -7831,6 +7865,7 @@
proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer);
proto.write(AFFINITY, affinity);
+ proto.write(HAS_CHILD_PIP_ACTIVITY, mChildPipActivity != null);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 5ffab48..a467d82 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -646,8 +646,12 @@
if (shouldDisableSnapshots()) {
return;
}
+ final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
+ if (displayContent == null) {
+ return;
+ }
mTmpTasks.clear();
- mService.mRoot.getDisplayContent(displayId).forAllTasks(task -> {
+ displayContent.forAllTasks(task -> {
// Since RecentsAnimation will handle task snapshot while switching apps with the best
// capture timing (e.g. IME window capture), No need additional task capture while task
// is controlled by RecentsAnimation.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 070a725..191c3a11 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2796,6 +2796,11 @@
return dc != null && dc.okToAnimate(ignoreFrozen);
}
+ boolean okToAnimate(boolean ignoreFrozen, boolean ignoreScreenOn) {
+ final DisplayContent dc = getDisplayContent();
+ return dc != null && dc.okToAnimate(ignoreFrozen, ignoreScreenOn);
+ }
+
@Override
public void commitPendingTransaction() {
scheduleAnimation();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 43dceed..0c9473a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -731,7 +731,7 @@
final TaskSnapshotController mTaskSnapshotController;
- final BlurController mBlurController = new BlurController();
+ final BlurController mBlurController;
boolean mIsTouchDevice;
boolean mIsFakeTouchDevice;
@@ -1024,6 +1024,10 @@
// Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead.
private float mLetterboxBackgroundWallpaperDarkScrimAlpha;
+ // horizontal position of a center of the letterboxed app window. 0 corresponds to the left
+ // side of the screen and 1.0 to the right side.
+ private float mLetterboxHorizontalPositionMultiplier;
+
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
final DisplayManager mDisplayManager;
@@ -1183,7 +1187,8 @@
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
return main(context, im, showBootMsgs, onlyCore, policy, atm,
- SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
+ new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,
+ SurfaceControl.Builder::new);
}
/**
@@ -1193,12 +1198,14 @@
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
- ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
+ ActivityTaskManagerService atm, DisplayWindowSettingsProvider
+ displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
- atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0);
+ atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
+ surfaceControlFactory), 0);
return sInstance;
}
@@ -1220,7 +1227,8 @@
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
- ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
+ ActivityTaskManagerService atm, DisplayWindowSettingsProvider
+ displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
installLock(this, INDEX_WINDOW);
@@ -1261,6 +1269,8 @@
com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
mLetterboxBackgroundWallpaperDarkScrimAlpha = context.getResources().getFloat(
com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
+ mLetterboxHorizontalPositionMultiplier = context.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -1370,7 +1380,7 @@
final String displaySettingsPath = Settings.Global.getString(resolver,
DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
- mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider();
+ mDisplayWindowSettingsProvider = displayWindowSettingsProvider;
if (displaySettingsPath != null) {
mDisplayWindowSettingsProvider.setBaseSettingsFilePath(displaySettingsPath);
}
@@ -1414,6 +1424,8 @@
setGlobalShadowSettings();
mAnrController = new AnrController(this);
mStartingSurfaceController = new StartingSurfaceController(this);
+
+ mBlurController = new BlurController(mContext, mPowerManager);
}
DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {
@@ -1736,8 +1748,11 @@
}
// Switch to listen to the {@link WindowToken token}'s configuration changes when
- // adding a window to the window context.
- if (mWindowContextListenerController.hasListener(windowContextToken)) {
+ // adding a window to the window context. Filter sub window type here because the sub
+ // window must be attached to the parent window, which is attached to the window context
+ // created window token.
+ if (!win.isChildWindow()
+ && mWindowContextListenerController.hasListener(windowContextToken)) {
final int windowContextType = mWindowContextListenerController
.getWindowType(windowContextToken);
if (type != windowContextType) {
@@ -4049,6 +4064,38 @@
return mLetterboxBackgroundWallpaperBlurRadius;
}
+ /*
+ * Gets horizontal position of a center of the letterboxed app window specified
+ * in {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}
+ * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the
+ * right side.
+ *
+ * <p>This value can be outside of [0, 1] range so clients need to check and default to the
+ * central position (0.5).
+ */
+ float getLetterboxHorizontalPositionMultiplier() {
+ return mLetterboxHorizontalPositionMultiplier;
+ }
+
+ /**
+ * Overrides horizontal position of a center of the letterboxed app window. If given value < 0
+ * or > 1, then it and a value of {@link
+ * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and
+ * central position (0.5) is used.
+ */
+ void setLetterboxHorizontalPositionMultiplier(float multiplier) {
+ mLetterboxHorizontalPositionMultiplier = multiplier;
+ }
+
+ /**
+ * Resets horizontal position of a center of the letterboxed app window to {@link
+ * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
+ */
+ void resetLetterboxHorizontalPositionMultiplier() {
+ mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
+ }
+
@Override
public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
if (!checkCallingPermission(
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 5942f34..68257d4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -143,6 +143,10 @@
return runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
case "get-letterbox-background-wallpaper-dark-scrim-alpha":
return runGetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
+ case "set-letterbox-horizontal-position-multiplier":
+ return runSeLetterboxHorizontalPositionMultiplier(pw);
+ case "get-letterbox-horizontal-position-multiplier":
+ return runGetLetterboxHorizontalPositionMultiplier(pw);
case "set-sandbox-display-apis":
return runSandboxDisplayApis(pw);
case "reset":
@@ -846,6 +850,43 @@
return 0;
}
+ private int runSeLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException {
+ final float multiplier;
+ try {
+ String arg = getNextArgRequired();
+ if ("reset".equals(arg)) {
+ synchronized (mInternal.mGlobalLock) {
+ mInternal.resetLetterboxHorizontalPositionMultiplier();
+ }
+ return 0;
+ }
+ multiplier = Float.parseFloat(arg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: bad multiplier format " + e);
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println(
+ "Error: 'reset' or multiplier should be provided as an argument " + e);
+ return -1;
+ }
+ synchronized (mInternal.mGlobalLock) {
+ mInternal.setLetterboxHorizontalPositionMultiplier(multiplier);
+ }
+ return 0;
+ }
+
+ private int runGetLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException {
+ synchronized (mInternal.mGlobalLock) {
+ final float multiplier = mInternal.getLetterboxHorizontalPositionMultiplier();
+ if (multiplier < 0) {
+ pw.println("Letterbox horizontal position multiplier is not set");
+ } else {
+ pw.println("Letterbox horizontal position multiplier is " + multiplier);
+ }
+ }
+ return 0;
+ }
+
private int runReset(PrintWriter pw) throws RemoteException {
int displayId = getDisplayId(getNextArg());
@@ -888,6 +929,9 @@
// set-letterbox-background-wallpaper-dark-scrim-alpha
mInternal.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
+ // set-letterbox-horizontal-position-multiplier
+ mInternal.resetLetterboxHorizontalPositionMultiplier();
+
// set-sandbox-display-apis
mInternal.setSandboxDisplayApis(displayId, /* sandboxDisplayApis= */ true);
@@ -954,6 +998,11 @@
pw.println(" letterbox background. If alpha < 0 or >= 1 both it and");
pw.println(" R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha are ignored and ");
pw.println(" 0.0 (transparent) is used instead.");
+ pw.println(" set-letterbox-horizontal-position-multiplier [reset|multiplier]");
+ pw.println(" get-letterbox-horizontal-position-multiplier");
+ pw.println(" horizontal position of a center of a letterboxed app. If it < 0 or > 1");
+ pw.println(" then both it and R.dimen.config_letterboxHorizontalPositionMultiplier");
+ pw.println(" are ignored and central position (0.5) is used.");
pw.println(" set-sandbox-display-apis [true|1|false|0]");
pw.println(" Sets override of Display APIs getRealSize / getRealMetrics to reflect ");
pw.println(" DisplayArea of the activity, or the window bounds if in letterbox or");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1ba57fd..cf9b88a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -173,6 +173,7 @@
import android.app.admin.FullyManagedDeviceProvisioningParams;
import android.app.admin.ManagedProfileProvisioningParams;
import android.app.admin.NetworkEvent;
+import android.app.admin.ParcelableGranteeMap;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
import android.app.admin.SecurityLog;
@@ -278,6 +279,7 @@
import android.telephony.data.ApnSetting;
import android.text.TextUtils;
import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
@@ -5649,41 +5651,33 @@
}
@Override
- public List<String> getKeyPairGrants(String callerPackage, String alias) {
+ public ParcelableGranteeMap getKeyPairGrants(String callerPackage, String alias) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
Preconditions.checkCallAuthorization(canManageCertificates(caller));
- return mInjector.binderWithCleanCallingIdentity(() -> {
+ final ArrayMap<Integer, Set<String>> result = new ArrayMap<>();
+ mInjector.binderWithCleanCallingIdentity(() -> {
try (KeyChainConnection keyChainConnection =
KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
- final List<String> result = new ArrayList<>();
final int[] granteeUids = keyChainConnection.getService().getGrants(alias);
final PackageManager pm = mInjector.getPackageManager(caller.getUserId());
- // TODO: Return Set<Set<String>> when AIDL supports it: b/136048684
- // Public API returns a set of sets, where each internal set contains all package
- // names corresponding to the same UID. For now a set of sets is marshalled as a
- // null-separated list.
for (final int uid : granteeUids) {
final String[] packages = pm.getPackagesForUid(uid);
if (packages == null) {
Slogf.wtf(LOG_TAG, "No packages found for uid " + uid);
continue;
}
- if (!result.isEmpty()) {
- result.add(null);
- }
- result.addAll(Arrays.asList(packages));
+ result.put(uid, new ArraySet<String>(packages));
}
- return result;
} catch (RemoteException e) {
Slogf.e(LOG_TAG, "Querying keypair grants", e);
} catch (InterruptedException e) {
Slogf.w(LOG_TAG, "Interrupted while querying keypair grants", e);
Thread.currentThread().interrupt();
}
- return Collections.emptyList();
});
+ return new ParcelableGranteeMap(result);
}
/**
@@ -8125,20 +8119,16 @@
+ " as device owner for user " + userId);
return false;
}
- if (admin == null
- || !isPackageInstalledForUser(admin.getPackageName(), userId)) {
- throw new IllegalArgumentException("Invalid component " + admin
- + " for device owner");
- }
+ Preconditions.checkArgument(admin != null);
final CallerIdentity caller = getCallerIdentity();
synchronized (getLockObject()) {
enforceCanSetDeviceOwnerLocked(caller, admin, userId);
+ Preconditions.checkArgument(isPackageInstalledForUser(admin.getPackageName(), userId),
+ "Invalid component " + admin + " for device owner");
final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId);
- if (activeAdmin == null
- || getUserData(userId).mRemovingAdmins.contains(admin)) {
- throw new IllegalArgumentException("Not active admin: " + admin);
- }
+ Preconditions.checkArgument(activeAdmin != null && !getUserData(
+ userId).mRemovingAdmins.contains(admin), "Not active admin: " + admin);
// Shutting down backup manager service permanently.
toggleBackupServiceActive(UserHandle.USER_SYSTEM, /* makeActive= */ false);
@@ -8527,20 +8517,16 @@
+ " as profile owner for user " + userHandle);
return false;
}
- if (who == null
- || !isPackageInstalledForUser(who.getPackageName(), userHandle)) {
- throw new IllegalArgumentException("Component " + who
- + " not installed for userId:" + userHandle);
- }
+ Preconditions.checkArgument(who != null);
final CallerIdentity caller = getCallerIdentity();
synchronized (getLockObject()) {
enforceCanSetProfileOwnerLocked(caller, who, userHandle);
-
+ Preconditions.checkArgument(isPackageInstalledForUser(who.getPackageName(), userHandle),
+ "Component " + who + " not installed for userId:" + userHandle);
final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
- if (admin == null || getUserData(userHandle).mRemovingAdmins.contains(who)) {
- throw new IllegalArgumentException("Not active admin: " + who);
- }
+ Preconditions.checkArgument(admin != null && !getUserData(
+ userHandle).mRemovingAdmins.contains(who), "Not active admin: " + who);
final int parentUserId = getProfileParentId(userHandle);
// When trying to set a profile owner on a new user, it may be that this user is
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 912b8ca..4c4c582 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -384,6 +384,7 @@
private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService";
private static final String GAME_MANAGER_SERVICE_CLASS =
"com.android.server.app.GameManagerService$Lifecycle";
+ private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -2637,6 +2638,12 @@
LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
t.traceEnd();
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
+ t.traceBegin("UwbService");
+ mSystemServiceManager.startService(UWB_SERVICE_CLASS);
+ t.traceEnd();
+ }
+
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index b136d00..83677c2 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -36,6 +36,10 @@
],
test_suites: ["general-tests"],
java_resources: [
+ ":PackageManagerTestOverlayActor",
+ ":PackageManagerTestOverlay",
+ ":PackageManagerTestOverlayTarget",
+ ":PackageManagerTestOverlayTargetNoOverlayable",
":PackageManagerTestAppDeclaresStaticLibrary",
":PackageManagerTestAppStub",
":PackageManagerTestAppUsesStaticLibrary",
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OverlayActorVisibilityTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OverlayActorVisibilityTest.kt
new file mode 100644
index 0000000..558d01ed
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OverlayActorVisibilityTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.After
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import java.io.File
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class OverlayActorVisibilityTest : BaseHostJUnit4Test() {
+
+ companion object {
+ private const val ACTOR_PKG_NAME = "com.android.server.pm.test.overlay.actor"
+ private const val ACTOR_APK = "PackageManagerTestOverlayActor.apk"
+ private const val TARGET_APK = "PackageManagerTestOverlayTarget.apk"
+ private const val OVERLAY_APK = "PackageManagerTestOverlay.apk"
+ private const val TARGET_NO_OVERLAYABLE_APK =
+ "PackageManagerTestOverlayTargetNoOverlayable.apk"
+
+ @get:ClassRule
+ val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
+ }
+
+ @get:Rule
+ val tempFolder = TemporaryFolder()
+
+ private val preparer: SystemPreparer = SystemPreparer(
+ tempFolder,
+ SystemPreparer.RebootStrategy.FULL,
+ deviceRebootRule
+ ) { this.device }
+
+ private val namedActorFile = File(
+ "/system/etc/sysconfig/com.android.server.pm.test.OverlayActorVisibilityTest.xml"
+ )
+
+ @Before
+ @After
+ fun uninstallPackages() {
+ device.uninstallPackages(ACTOR_APK, TARGET_APK, OVERLAY_APK)
+ }
+
+ @Before
+ fun pushSysConfigFile() {
+ // In order for the test app to be the verification agent, it needs a permission file
+ // which can be pushed onto the system and removed afterwards.
+ // language=XML
+ val file = tempFolder.newFile().apply {
+ """
+ <config>
+ <named-actor
+ namespace="androidTest"
+ name="OverlayActorVisibilityTest"
+ package="$ACTOR_PKG_NAME"
+ />
+ </config>
+ """
+ .trimIndent()
+ .let { writeText(it) }
+ }
+
+ preparer.pushFile(file, namedActorFile.toString())
+ .reboot()
+ }
+
+ @After
+ fun deleteSysConfigFile() {
+ preparer.deleteFile(namedActorFile.toString())
+ .reboot()
+ }
+
+ @Test
+ fun testVisibilityByOverlayable() {
+ assertThat(device.installJavaResourceApk(tempFolder, ACTOR_APK, false)).isNull()
+ assertThat(device.installJavaResourceApk(tempFolder, OVERLAY_APK, false)).isNull()
+ assertThat(device.installJavaResourceApk(tempFolder, TARGET_NO_OVERLAYABLE_APK, false))
+ .isNull()
+
+ runDeviceTests(
+ ACTOR_PKG_NAME, "$ACTOR_PKG_NAME.OverlayableVisibilityTest",
+ "verifyNotVisible"
+ )
+
+ assertThat(device.installJavaResourceApk(tempFolder, TARGET_APK, true)).isNull()
+
+ assertWithMessage(device.executeShellCommand("dumpsys package $OVERLAY_APK"))
+
+ runDeviceTests(
+ ACTOR_PKG_NAME, "$ACTOR_PKG_NAME.OverlayableVisibilityTest",
+ "verifyVisible"
+ )
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/Android.bp
new file mode 100644
index 0000000..92dcd34
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/Android.bp
@@ -0,0 +1,26 @@
+//
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "PackageManagerTestOverlay",
+ srcs: [
+ "src/**/*.kt",
+ ],
+}
diff --git a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/AndroidManifest.xml
similarity index 64%
copy from packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/Overlay/AndroidManifest.xml
index b8ea622..21e4432 100644
--- a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
@@ -13,10 +13,10 @@
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" >
- <solid
- android:color="?android:attr/textColorSecondary" />
- <corners android:radius="2dp" />
-</shape>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.overlay">
+ <application/>
+ <overlay android:targetPackage="com.android.server.pm.test.overlay.target"
+ android:targetName="Testing"/>
+</manifest>
diff --git a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/res/values/values.xml
similarity index 68%
copy from packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/Overlay/res/values/values.xml
index b8ea622..f0b8586 100644
--- a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/res/values/values.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
@@ -13,10 +13,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" >
- <solid
- android:color="?android:attr/textColorSecondary" />
- <corners android:radius="2dp" />
-</shape>
+
+<resources>
+ <string name="policy_public">You have been overlaid</string>
+</resources>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
new file mode 100644
index 0000000..5718474
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
@@ -0,0 +1,33 @@
+// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "PackageManagerTestOverlayActor",
+ srcs: ["src/**/*.kt"],
+ static_libs: [
+ "androidx.test.runner",
+ "junit",
+ "kotlin-test",
+ "truth-prebuilt",
+ ],
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/AndroidManifest.xml
new file mode 100644
index 0000000..a92a14f
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.overlay.actor"
+ >
+
+ <application/>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.pm.test.overlay.actor"
+ />
+
+</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/src/com/android/server/pm/test/overlay/actor/OverlayableVisibilityTest.kt b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/src/com/android/server/pm/test/overlay/actor/OverlayableVisibilityTest.kt
new file mode 100644
index 0000000..7537247f
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/src/com/android/server/pm/test/overlay/actor/OverlayableVisibilityTest.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.pm.test.overlay.actor
+
+import android.content.Context
+import android.content.pm.PackageManager
+import androidx.test.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import kotlin.test.assertFailsWith
+
+class OverlayableVisibilityTest {
+
+ companion object {
+ private const val TARGET_PACKAGE = "com.android.server.pm.test.overlay.target"
+ private const val OVERLAY_PACKAGE = "com.android.server.pm.test.overlay"
+ }
+
+ private val context: Context = InstrumentationRegistry.getContext()
+ private val packageManager = context.packageManager
+
+ @Test
+ fun verifyVisible() {
+ assertThat(packageManager.getApplicationInfo(TARGET_PACKAGE, 0)).isNotNull()
+ assertThat(packageManager.getApplicationInfo(OVERLAY_PACKAGE, 0)).isNotNull()
+ }
+
+ @Test
+ fun verifyNotVisible() {
+ assertFailsWith(PackageManager.NameNotFoundException::class) {
+ packageManager.getApplicationInfo(TARGET_PACKAGE, 0)
+ }
+ assertFailsWith(PackageManager.NameNotFoundException::class) {
+ packageManager.getApplicationInfo(OVERLAY_PACKAGE, 0)
+ }
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/Android.bp
new file mode 100644
index 0000000..2bb6b82
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "PackageManagerTestOverlayTarget",
+ defaults: ["cts_support_defaults"],
+ sdk_version: "current",
+ resource_dirs: [
+ "res",
+ "res_overlayable",
+ ],
+}
+
+android_test_helper_app {
+ name: "PackageManagerTestOverlayTargetNoOverlayable",
+ defaults: ["cts_support_defaults"],
+ sdk_version: "current",
+ resource_dirs: [
+ "res",
+ ],
+}
diff --git a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/AndroidManifest.xml
similarity index 68%
copy from packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/AndroidManifest.xml
index b8ea622..6038cb1 100644
--- a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
@@ -13,10 +13,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" >
- <solid
- android:color="?android:attr/textColorSecondary" />
- <corners android:radius="2dp" />
-</shape>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.overlay.target">
+</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/assets/asset.txt b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/assets/asset.txt
new file mode 100644
index 0000000..4625e3b
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/assets/asset.txt
@@ -0,0 +1 @@
+Not overlaid
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res/values/public.xml
similarity index 68%
copy from packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res/values/public.xml
index b8ea622..283f5c1 100644
--- a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res/values/public.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
@@ -13,10 +13,9 @@
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" >
- <solid
- android:color="?android:attr/textColorSecondary" />
- <corners android:radius="2dp" />
-</shape>
+
+<resources>
+ <public-group type="string" first-id="0x7f010000">
+ <public name="policy_public" />
+ </public-group>
+</resources>
diff --git a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res/values/values.xml
similarity index 68%
copy from packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res/values/values.xml
index b8ea622..822194f 100644
--- a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res/values/values.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
@@ -13,10 +13,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" >
- <solid
- android:color="?android:attr/textColorSecondary" />
- <corners android:radius="2dp" />
-</shape>
+
+<resources>
+ <string name="policy_public">Not overlaid</string>
+</resources>
diff --git a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res_overlayable/values/overlayable.xml
similarity index 68%
rename from packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
rename to services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res_overlayable/values/overlayable.xml
index b8ea622..0100389 100644
--- a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/res_overlayable/values/overlayable.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
@@ -13,10 +13,11 @@
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" >
- <solid
- android:color="?android:attr/textColorSecondary" />
- <corners android:radius="2dp" />
-</shape>
+
+<resources>
+ <overlayable name="Testing" actor="overlay://androidTest/OverlayActorVisibilityTest">
+ <policy type="public">
+ <item type="string" name="policy_public" />
+ </policy>
+ </overlayable>
+</resources>
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index dce853a..4de8d52 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -235,9 +235,23 @@
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https"/>
- <data android:path="/sub5"/>
- <data android:host="example5.com"/>
- <data android:host="invalid5"/>
+ <data android:path="/sub6"/>
+ <data android:host="example6.com"/>
+ <data android:host="invalid6"/>
+ </intent-filter>
+ <intent-filter android:autoVerify="$autoVerify">
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="example7.com"/>
+ <intent-filter android:autoVerify="$autoVerify">
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="https"/>
+ </intent-filter>
+ <intent-filter android:autoVerify="$autoVerify">
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:path="/sub7"/>
</intent-filter>
</xml>
""".trimIndent()
@@ -324,6 +338,30 @@
addDataAuthority("invalid6", null)
}
)
+ addIntent(
+ ParsedIntentInfo().apply {
+ setAutoVerify(autoVerify)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataAuthority("example7.com", null)
+ }
+ )
+ addIntent(
+ ParsedIntentInfo().apply {
+ setAutoVerify(autoVerify)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("https")
+ }
+ )
+ addIntent(
+ ParsedIntentInfo().apply {
+ setAutoVerify(autoVerify)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataPath("/sub7", PatternMatcher.PATTERN_LITERAL)
+ }
+ )
},
)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java
index 14c02d5..0a5a3bf 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationJavaUtil.java
@@ -20,11 +20,14 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager;
+import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainVerificationManager;
import com.android.server.pm.verify.domain.DomainVerificationService;
+import java.util.List;
import java.util.Set;
+import java.util.SortedSet;
import java.util.UUID;
/**
@@ -58,4 +61,14 @@
throws PackageManager.NameNotFoundException {
return manager.setDomainVerificationUserSelection(domainSetId, domains, enabled);
}
+
+ static SortedSet<DomainOwner> getOwnersForDomain(@NonNull DomainVerificationManager manager,
+ @Nullable String domain) {
+ return manager.getOwnersForDomain(domain);
+ }
+
+ static List<DomainOwner> getOwnersForDomain(@NonNull DomainVerificationService service,
+ @Nullable String domain, @UserIdInt int userId) {
+ return service.getOwnersForDomain(domain, userId);
+ }
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index adc1dab..3838f68 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -22,6 +22,7 @@
import android.content.pm.PackageUserState
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.verify.domain.DomainOwner
import android.content.pm.verify.domain.DomainVerificationInfo
import android.content.pm.verify.domain.DomainVerificationManager
import android.content.pm.verify.domain.DomainVerificationUserState
@@ -33,6 +34,7 @@
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageSettings
+import com.android.server.pm.verify.domain.DomainVerificationManagerStub
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
@@ -108,7 +110,7 @@
assertThat(infoOne.packageName).isEqualTo(pkgWithDomains.getName())
assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(mapOf(
DOMAIN_1 to DomainVerificationInfo.STATE_NO_RESPONSE,
- DOMAIN_2 to DomainVerificationInfo.STATE_NO_RESPONSE,
+ DOMAIN_2 to DomainVerificationInfo.STATE_NO_RESPONSE
))
assertThat(service.getDomainVerificationInfo(pkgWithoutDomains.getName())).isNull()
@@ -155,7 +157,7 @@
}
map.clear()
- assertFailsWith(PackageManager.NameNotFoundException::class){
+ assertFailsWith(PackageManager.NameNotFoundException::class) {
service.setStatus(UUID_ONE, setOf(DOMAIN_1), 1100)
}
}
@@ -168,7 +170,7 @@
val map = mutableMapOf(pkg1.getName() to pkg1, pkg2.getName() to pkg2)
val service = makeService(map::get).apply { addPackages(pkg1, pkg2) }
- service.setDomainVerificationLinkHandlingAllowed(PKG_ONE, false, 0);
+ service.setDomainVerificationLinkHandlingAllowed(PKG_ONE, false, 0)
// Should edit same package, same user
assertThat(service.getDomainVerificationUserState(PKG_ONE, 0)
@@ -182,8 +184,8 @@
assertThat(service.getDomainVerificationUserState(PKG_TWO, 0)
?.isLinkHandlingAllowed).isEqualTo(true)
- assertFailsWith(PackageManager.NameNotFoundException::class){
- service.setDomainVerificationLinkHandlingAllowed("invalid.pkg.name", false, 0);
+ assertFailsWith(PackageManager.NameNotFoundException::class) {
+ service.setDomainVerificationLinkHandlingAllowed("invalid.pkg.name", false, 0)
}
}
@@ -232,7 +234,7 @@
.isEqualTo(DomainVerificationManager.ERROR_UNABLE_TO_APPROVE)
map.clear()
- assertFailsWith(PackageManager.NameNotFoundException::class){
+ assertFailsWith(PackageManager.NameNotFoundException::class) {
service.setUserSelection(UUID_ONE, setOf(DOMAIN_1), true, 0)
}
}
@@ -253,7 +255,7 @@
assertThat(infoOne.isLinkHandlingAllowed).isTrue()
assertThat(infoOne.hostToStateMap).containsExactlyEntriesIn(mapOf(
DOMAIN_1 to DomainVerificationUserState.DOMAIN_STATE_NONE,
- DOMAIN_2 to DomainVerificationUserState.DOMAIN_STATE_NONE,
+ DOMAIN_2 to DomainVerificationUserState.DOMAIN_STATE_NONE
))
val infoTwo = service.getDomainVerificationUserState(pkgWithoutDomains.getName(), 0)
@@ -286,7 +288,21 @@
addPackages(pkg1, pkg2)
}
- assertThat(service.getOwnersForDomain(DOMAIN_1, 0)).isEmpty()
+ // DomainVerificationManager converts the owner list to a SortedSet, so test that, too
+ val manager0 = makeManager(service, 0)
+ val manager1 = makeManager(service, 1)
+
+ listOf(DOMAIN_1, "").forEach {
+ assertThat(service.getOwnersForDomain(it, 0)).isEmpty()
+ assertThat(manager0.getOwnersForDomain(it)).isEmpty()
+ }
+
+ assertFailsWith(NullPointerException::class) {
+ DomainVerificationJavaUtil.getOwnersForDomain(service, null, 0)
+ }
+ assertFailsWith(NullPointerException::class) {
+ DomainVerificationJavaUtil.getOwnersForDomain(manager0, null)
+ }
assertThat(
service.setStatus(
@@ -306,25 +322,33 @@
service.setUserSelection(pkg1.domainSetId, setOf(DOMAIN_2), true, 0)
service.getOwnersForDomain(DOMAIN_1, 0).let {
- assertThat(it).hasSize(2)
- assertThat(it[0].packageName).isEqualTo(pkg1.getName())
- assertThat(it[0].isOverrideable).isEqualTo(false)
- assertThat(it[1].packageName).isEqualTo(pkg2.getName())
- assertThat(it[1].isOverrideable).isEqualTo(false)
+ assertThat(it).containsExactly(
+ DomainOwner(pkg1.getName(), false),
+ DomainOwner(pkg2.getName(), false)
+ ).inOrder()
+ }
+ manager0.getOwnersForDomain(DOMAIN_1).let {
+ assertThat(it).containsExactly(
+ DomainOwner(pkg1.getName(), false),
+ DomainOwner(pkg2.getName(), false)
+ ).inOrder()
}
service.getOwnersForDomain(DOMAIN_2, 0).let {
- assertThat(it).hasSize(1)
- assertThat(it.single().packageName).isEqualTo(pkg1.getName())
- assertThat(it.single().isOverrideable).isEqualTo(true)
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+ }
+ manager0.getOwnersForDomain(DOMAIN_2).let {
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
}
assertThat(service.getOwnersForDomain(DOMAIN_2, 1)).isEmpty()
+ assertThat(manager1.getOwnersForDomain(DOMAIN_2)).isEmpty()
service.setUserSelection(pkg1.domainSetId, setOf(DOMAIN_2), true, 1)
service.getOwnersForDomain(DOMAIN_2, 1).let {
- assertThat(it).hasSize(1)
- assertThat(it.single().packageName).isEqualTo(pkg1.getName())
- assertThat(it.single().isOverrideable).isEqualTo(true)
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+ }
+ manager1.getOwnersForDomain(DOMAIN_2).let {
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
}
// "Uninstall" the package from user 0 and ensure it's stripped from the results
@@ -332,9 +356,10 @@
service.clearPackageForUser(pkg1.getName(), 0)
service.getOwnersForDomain(DOMAIN_1, 0).let {
- assertThat(it).hasSize(1)
- assertThat(it.single().packageName).isEqualTo(pkg2.getName())
- assertThat(it.single().isOverrideable).isEqualTo(false)
+ assertThat(it).containsExactly(DomainOwner(pkg2.getName(), false))
+ }
+ manager0.getOwnersForDomain(DOMAIN_1).let {
+ assertThat(it).containsExactly(DomainOwner(pkg2.getName(), false))
}
// Domain 2 user selection gone for user 0
@@ -342,26 +367,33 @@
// Domain 2 user selection still around for user 1
service.getOwnersForDomain(DOMAIN_2, 1).let {
- assertThat(it).hasSize(1)
- assertThat(it.single().packageName).isEqualTo(pkg1.getName())
- assertThat(it.single().isOverrideable).isEqualTo(true)
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+ }
+ manager1.getOwnersForDomain(DOMAIN_2).let {
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
}
// Now assert for user 1 that it was unaffected by the change to user 0
service.getOwnersForDomain(DOMAIN_1, 1).let {
- assertThat(it).hasSize(2)
- assertThat(it[0].packageName).isEqualTo(pkg1.getName())
- assertThat(it[0].isOverrideable).isEqualTo(false)
- assertThat(it[1].packageName).isEqualTo(pkg2.getName())
- assertThat(it[1].isOverrideable).isEqualTo(false)
+ assertThat(it).containsExactly(
+ DomainOwner(pkg1.getName(), false),
+ DomainOwner(pkg2.getName(), false)
+ ).inOrder()
+ }
+ manager1.getOwnersForDomain(DOMAIN_1).let {
+ assertThat(it).containsExactly(
+ DomainOwner(pkg1.getName(), false),
+ DomainOwner(pkg2.getName(), false)
+ ).inOrder()
}
service.setUserSelection(pkg1.domainSetId, setOf(DOMAIN_2), true, 0)
service.getOwnersForDomain(DOMAIN_2, 1).let {
- assertThat(it).hasSize(1)
- assertThat(it.single().packageName).isEqualTo(pkg1.getName())
- assertThat(it.single().isOverrideable).isEqualTo(true)
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
+ }
+ manager1.getOwnersForDomain(DOMAIN_2).let {
+ assertThat(it).containsExactly(DomainOwner(pkg1.getName(), true))
}
// "Reinstall" the package to user 0
@@ -369,13 +401,15 @@
// This state should have been cleared when the package was uninstalled
assertThat(service.getOwnersForDomain(DOMAIN_2, 0)).isEmpty()
+ assertThat(manager0.getOwnersForDomain(DOMAIN_2)).isEmpty()
// Other package unaffected
service.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_2), true, 0)
service.getOwnersForDomain(DOMAIN_2, 0).let {
- assertThat(it).hasSize(1)
- assertThat(it.single().packageName).isEqualTo(pkg2.getName())
- assertThat(it.single().isOverrideable).isEqualTo(true)
+ assertThat(it).containsExactly(DomainOwner(pkg2.getName(), true))
+ }
+ manager0.getOwnersForDomain(DOMAIN_2).let {
+ assertThat(it).containsExactly(DomainOwner(pkg2.getName(), true))
}
}
@@ -480,7 +514,7 @@
}
)
}
- },
+ }
)
whenever(activities) { activityList }
@@ -495,6 +529,10 @@
whenever(readUserState(1)) { pkgUserState1() }
}
- fun DomainVerificationService.addPackages(vararg pkgSettings: PackageSetting) =
+ private fun DomainVerificationService.addPackages(vararg pkgSettings: PackageSetting) =
pkgSettings.forEach(::addPackage)
+
+ private fun makeManager(service: DomainVerificationService, userId: Int) =
+ DomainVerificationManager(mockThrowOnUnmocked { whenever(this.userId) { userId } },
+ DomainVerificationManagerStub(service))
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt
new file mode 100644
index 0000000..98634b2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationValidIntentTest.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.pm.test.verify.domain
+
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import com.android.server.pm.verify.domain.DomainVerificationUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class DomainVerificationValidIntentTest {
+
+ companion object {
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun parameters(): Array<Params> {
+ val succeeding = mutableListOf<Params>()
+ val failing = mutableListOf<Params>()
+
+ // Start with the base intent
+ val base = Params(categorySet = emptySet()).also { succeeding += it }
+
+ // Add all explicit supported categorySet
+ succeeding += base.copy(
+ categorySet = setOf(Intent.CATEGORY_BROWSABLE),
+ matchDefaultOnly = true
+ )
+
+ failing += base.copy(
+ categorySet = setOf(Intent.CATEGORY_BROWSABLE),
+ matchDefaultOnly = false
+ )
+
+ succeeding += listOf(true, false).map {
+ base.copy(
+ categorySet = setOf(Intent.CATEGORY_DEFAULT),
+ matchDefaultOnly = it
+ )
+ }
+
+ succeeding += listOf(true, false).map {
+ base.copy(
+ categorySet = setOf(Intent.CATEGORY_BROWSABLE, Intent.CATEGORY_DEFAULT),
+ matchDefaultOnly = it
+ )
+ }
+
+ // Fail on unsupported category
+ failing += listOf(
+ emptySet(),
+ setOf(Intent.CATEGORY_BROWSABLE),
+ setOf(Intent.CATEGORY_DEFAULT),
+ setOf(Intent.CATEGORY_BROWSABLE, Intent.CATEGORY_DEFAULT)
+ ).map { base.copy(categorySet = it + "invalid.CATEGORY") }
+
+ // Fail on unsupported action
+ failing += base.copy(action = Intent.ACTION_SEND)
+
+ // Fail on unsupported domain
+ failing += base.copy(domain = "invalid")
+
+ // Fail on empty domains
+ failing += base.copy(domain = "")
+
+ // Fail on missing scheme
+ failing += base.copy(
+ uriFunction = { Uri.Builder().authority("test.com").build() }
+ )
+
+ // Fail on missing host
+ failing += base.copy(
+ domain = "",
+ uriFunction = { Uri.Builder().scheme("https").build() }
+ )
+
+ succeeding.forEach { it.expected = true }
+ failing.forEach { it.expected = false }
+ return (succeeding + failing).toTypedArray()
+ }
+
+ data class Params(
+ val action: String = Intent.ACTION_VIEW,
+ val categorySet: Set<String> = mutableSetOf(),
+ val domain: String = "test.com",
+ val matchDefaultOnly: Boolean = true,
+ var expected: Boolean? = null,
+ val uriFunction: (domain: String) -> Uri = { Uri.parse("https://$it") }
+ ) {
+ val intent = Intent(action, uriFunction(domain)).apply {
+ categorySet.forEach(::addCategory)
+ }
+
+ override fun toString() = intent.toShortString(false, false, false, false) +
+ ", matchDefaultOnly = $matchDefaultOnly, expected = $expected"
+ }
+ }
+
+ @Parameterized.Parameter(0)
+ lateinit var params: Params
+
+ @Test
+ fun verify() {
+ val flags = if (params.matchDefaultOnly) PackageManager.MATCH_DEFAULT_ONLY else 0
+ assertThat(DomainVerificationUtils.isDomainVerificationIntent(params.intent, flags))
+ .isEqualTo(params.expected)
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index edfc21d..7654093 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -2223,7 +2223,11 @@
}
@Test
- public void minWindow() {
+ public void minWindowChangeEnabled() {
+ doReturn(true).when(
+ () -> CompatChanges.isChangeEnabled(
+ eq(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS),
+ anyString(), any(UserHandle.class)));
final long minWindow = 73;
setDeviceConfigLong(KEY_MIN_WINDOW, minWindow);
@@ -2239,6 +2243,26 @@
}
@Test
+ public void minWindowChangeDisabled() {
+ doReturn(false).when(
+ () -> CompatChanges.isChangeEnabled(
+ eq(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS),
+ anyString(), any(UserHandle.class)));
+ final long minWindow = 73;
+ setDeviceConfigLong(KEY_MIN_WINDOW, minWindow);
+
+ // 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC.
+ for (int window = 1; window <= minWindow; window++) {
+ final PendingIntent pi = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, 0, window, pi, 0, 0, TEST_CALLING_UID, null);
+
+ assertEquals(1, mService.mAlarmStore.size());
+ final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0);
+ assertEquals(window, a.windowLength);
+ }
+ }
+
+ @Test
public void denyListPackagesAdded() {
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{"p1", "p2", "p3"});
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, "p2,p4,p5");
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
index 924ad7f..76f7e80 100644
--- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -35,7 +35,6 @@
import android.os.Message;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
-import android.util.ArrayMap;
import android.util.LongSparseArray;
import androidx.test.InstrumentationRegistry;
@@ -68,7 +67,6 @@
private File mBlobsDir;
private LongSparseArray<BlobStoreSession> mUserSessions;
- private ArrayMap<BlobHandle, BlobMetadata> mUserBlobs;
private static final String TEST_PKG1 = "com.example1";
private static final String TEST_PKG2 = "com.example2";
@@ -99,10 +97,8 @@
mHandler = new TestHandler(Looper.getMainLooper());
mService = new BlobStoreManagerService(mContext, new TestInjector());
mUserSessions = new LongSparseArray<>();
- mUserBlobs = new ArrayMap<>();
mService.addUserSessionsForTest(mUserSessions, UserHandle.myUserId());
- mService.addUserBlobsForTest(mUserBlobs, UserHandle.myUserId());
}
@After
@@ -147,7 +143,7 @@
final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobId1, blobFile1,
blobHandle1, true /* hasLeases */);
doReturn(true).when(blobMetadata1).isACommitter(TEST_PKG1, TEST_UID1);
- mUserBlobs.put(blobHandle1, blobMetadata1);
+ addBlob(blobHandle1, blobMetadata1);
final long blobId2 = 347;
final File blobFile2 = mock(File.class);
@@ -156,7 +152,7 @@
final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2,
blobHandle2, false /* hasLeases */);
doReturn(false).when(blobMetadata2).isACommitter(TEST_PKG1, TEST_UID1);
- mUserBlobs.put(blobHandle2, blobMetadata2);
+ addBlob(blobHandle2, blobMetadata2);
final long blobId3 = 49875;
final File blobFile3 = mock(File.class);
@@ -165,7 +161,7 @@
final BlobMetadata blobMetadata3 = createBlobMetadataMock(blobId3, blobFile3,
blobHandle3, true /* hasLeases */);
doReturn(true).when(blobMetadata3).isACommitter(TEST_PKG1, TEST_UID1);
- mUserBlobs.put(blobHandle3, blobMetadata3);
+ addBlob(blobHandle3, blobMetadata3);
mService.addActiveIdsForTest(sessionId1, sessionId2, sessionId3, sessionId4,
blobId1, blobId2, blobId3);
@@ -197,10 +193,10 @@
verify(blobMetadata2).destroy();
verify(blobMetadata3).destroy();
- assertThat(mUserBlobs.size()).isEqualTo(1);
- assertThat(mUserBlobs.get(blobHandle1)).isNotNull();
- assertThat(mUserBlobs.get(blobHandle2)).isNull();
- assertThat(mUserBlobs.get(blobHandle3)).isNull();
+ assertThat(mService.getBlobsCountForTest()).isEqualTo(1);
+ assertThat(mService.getBlobForTest(blobHandle1)).isNotNull();
+ assertThat(mService.getBlobForTest(blobHandle2)).isNull();
+ assertThat(mService.getBlobForTest(blobHandle3)).isNull();
assertThat(mService.getActiveIdsForTest()).containsExactly(
sessionId2, sessionId3, blobId1);
@@ -293,7 +289,7 @@
"label1", System.currentTimeMillis() - 2000, "tag1");
final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobId1, blobFile1, blobHandle1,
true /* hasLeases */);
- mUserBlobs.put(blobHandle1, blobMetadata1);
+ addBlob(blobHandle1, blobMetadata1);
final long blobId2 = 78974;
final File blobFile2 = mock(File.class);
@@ -301,7 +297,7 @@
"label2", System.currentTimeMillis() + 30000, "tag2");
final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobId2, blobFile2, blobHandle2,
true /* hasLeases */);
- mUserBlobs.put(blobHandle2, blobMetadata2);
+ addBlob(blobHandle2, blobMetadata2);
final long blobId3 = 97;
final File blobFile3 = mock(File.class);
@@ -309,7 +305,7 @@
"label3", System.currentTimeMillis() + 4400000, "tag3");
final BlobMetadata blobMetadata3 = createBlobMetadataMock(blobId3, blobFile3, blobHandle3,
false /* hasLeases */);
- mUserBlobs.put(blobHandle3, blobMetadata3);
+ addBlob(blobHandle3, blobMetadata3);
mService.addActiveIdsForTest(blobId1, blobId2, blobId3);
@@ -321,8 +317,8 @@
verify(blobMetadata2, never()).destroy();
verify(blobMetadata3).destroy();
- assertThat(mUserBlobs.size()).isEqualTo(1);
- assertThat(mUserBlobs.get(blobHandle2)).isNotNull();
+ assertThat(mService.getBlobsCountForTest()).isEqualTo(1);
+ assertThat(mService.getBlobForTest(blobHandle2)).isNotNull();
assertThat(mService.getActiveIdsForTest()).containsExactly(blobId2);
assertThat(mService.getKnownIdsForTest()).containsExactly(blobId1, blobId2, blobId3);
@@ -336,21 +332,21 @@
doReturn(size1).when(blobMetadata1).getSize();
doReturn(true).when(blobMetadata1).isALeasee(TEST_PKG1, TEST_UID1);
doReturn(true).when(blobMetadata1).isALeasee(TEST_PKG2, TEST_UID2);
- mUserBlobs.put(mock(BlobHandle.class), blobMetadata1);
+ addBlob(mock(BlobHandle.class), blobMetadata1);
final BlobMetadata blobMetadata2 = mock(BlobMetadata.class);
final long size2 = 89475;
doReturn(size2).when(blobMetadata2).getSize();
doReturn(false).when(blobMetadata2).isALeasee(TEST_PKG1, TEST_UID1);
doReturn(true).when(blobMetadata2).isALeasee(TEST_PKG2, TEST_UID2);
- mUserBlobs.put(mock(BlobHandle.class), blobMetadata2);
+ addBlob(mock(BlobHandle.class), blobMetadata2);
final BlobMetadata blobMetadata3 = mock(BlobMetadata.class);
final long size3 = 328732;
doReturn(size3).when(blobMetadata3).getSize();
doReturn(true).when(blobMetadata3).isALeasee(TEST_PKG1, TEST_UID1);
doReturn(false).when(blobMetadata3).isALeasee(TEST_PKG2, TEST_UID2);
- mUserBlobs.put(mock(BlobHandle.class), blobMetadata3);
+ addBlob(mock(BlobHandle.class), blobMetadata3);
// Verify usage is calculated correctly
assertThat(mService.getTotalUsageBytesLocked(TEST_UID1, TEST_PKG1))
@@ -388,6 +384,11 @@
return blobMetadata;
}
+ private void addBlob(BlobHandle blobHandle, BlobMetadata blobMetadata) {
+ doReturn(blobHandle).when(blobMetadata).getBlobHandle();
+ mService.addBlobLocked(blobMetadata);
+ }
+
private class TestHandler extends Handler {
TestHandler(Looper looper) {
super(looper);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 4bab8e5..6468790 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -81,6 +81,7 @@
import android.os.SystemClock;
import android.platform.test.annotations.LargeTest;
import android.provider.DeviceConfig;
+import android.util.ArraySet;
import android.util.SparseBooleanArray;
import androidx.test.runner.AndroidJUnit4;
@@ -254,6 +255,9 @@
any());
mUidObserver = uidObserverCaptor.getValue();
mSourceUid = AppGlobals.getPackageManager().getPackageUid(SOURCE_PACKAGE, 0, 0);
+ // Need to do this since we're using a mock JS and not a real object.
+ doReturn(new ArraySet<>(new String[]{SOURCE_PACKAGE}))
+ .when(mJobSchedulerService).getPackagesForUidLocked(mSourceUid);
} catch (RemoteException e) {
fail(e.getMessage());
}
@@ -1803,12 +1807,10 @@
setStandbyBucket(ACTIVE_INDEX, fgStateChanger);
setProcessState(ActivityManager.PROCESS_STATE_BACKUP, fgChangerUid);
- IPackageManager packageManager = AppGlobals.getPackageManager();
- spyOn(packageManager);
- doReturn(new String[]{unaffectedPkgName})
- .when(packageManager).getPackagesForUid(unaffectedUid);
- doReturn(new String[]{fgChangerPkgName})
- .when(packageManager).getPackagesForUid(fgChangerUid);
+ doReturn(new ArraySet<>(new String[]{unaffectedPkgName}))
+ .when(mJobSchedulerService).getPackagesForUidLocked(unaffectedUid);
+ doReturn(new ArraySet<>(new String[]{fgChangerPkgName}))
+ .when(mJobSchedulerService).getPackagesForUidLocked(fgChangerUid);
synchronized (mQuotaController.mLock) {
mQuotaController.maybeStartTrackingJobLocked(unaffected, null);
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index d7fbd49..9d055e0 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -37,6 +37,7 @@
"services.net",
"services.people",
"services.usage",
+ "services.uwb",
"guava",
"androidx.test.core",
"androidx.test.ext.truth",
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index 5bef877..e9b5b62 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -184,6 +184,7 @@
false /* callerInstantApp */,
null /* resolvedType */,
null /* requiredPermissions */,
+ null /* excludedPermissions */,
0 /* appOp */,
null /* options */,
new ArrayList<>(receivers), // Make a copy to not affect the original list.
diff --git a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
index 3231f62..6ca1102 100644
--- a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java
@@ -18,6 +18,8 @@
import static com.android.server.am.MeasuredEnergySnapshot.UNAVAILABLE;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -224,15 +226,15 @@
}
@Test
- public void testGetNumOtherOrdinals() {
+ public void testGetOtherOrdinalNames() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
- assertEquals(3, snapshot.getNumOtherOrdinals());
+ assertThat(snapshot.getOtherOrdinalNames()).asList().containsExactly("GPU", "HPU", "IPU");
}
@Test
- public void testGetNumOtherOrdinals_none() {
+ public void testGetOtherOrdinalNames_none() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(SOME_ID_CONSUMER_MAP);
- assertEquals(0, snapshot.getNumOtherOrdinals());
+ assertEquals(0, snapshot.getOtherOrdinalNames().length);
}
private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) {
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 4240581..b552fd5 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -32,6 +32,8 @@
import androidx.test.core.app.ApplicationProvider;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -203,7 +205,7 @@
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
// Set schema1
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -280,7 +282,7 @@
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -353,7 +355,7 @@
@Test
public void testSetSchema_defaultPlatformVisible() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -372,7 +374,7 @@
@Test
public void testSetSchema_platformHidden() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -391,7 +393,7 @@
@Test
public void testSetSchema_defaultNotPackageAccessible() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -419,7 +421,7 @@
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
index 8d35ebe..11ae76b 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
@@ -28,6 +28,8 @@
import androidx.test.core.app.ApplicationProvider;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -78,13 +80,9 @@
@Test
public void testValidPackageName() {
assertThat(VisibilityStore.PACKAGE_NAME)
- .doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.PACKAGE_DELIMITER));
assertThat(VisibilityStore.PACKAGE_NAME)
- .doesNotContain(
- ""
- + AppSearchImpl
- .DATABASE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.DATABASE_DELIMITER));
}
/**
@@ -93,13 +91,9 @@
@Test
public void testValidDatabaseName() {
assertThat(VisibilityStore.DATABASE_NAME)
- .doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.PACKAGE_DELIMITER));
assertThat(VisibilityStore.DATABASE_NAME)
- .doesNotContain(
- ""
- + AppSearchImpl
- .DATABASE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.DATABASE_DELIMITER));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index ba4d585..380d9be 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -16,6 +16,10 @@
package com.android.server.appsearch.external.localstorage;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.addPrefixToDocument;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefixesFromDocument;
+
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.expectThrows;
@@ -35,8 +39,10 @@
import androidx.test.core.app.ApplicationProvider;
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.proto.DocumentProto;
import com.android.server.appsearch.proto.GetOptimizeInfoResultProto;
+import com.android.server.appsearch.proto.PersistType;
import com.android.server.appsearch.proto.PropertyConfigProto;
import com.android.server.appsearch.proto.PropertyProto;
import com.android.server.appsearch.proto.SchemaProto;
@@ -47,6 +53,7 @@
import com.android.server.appsearch.proto.TermMatchType;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
@@ -54,6 +61,7 @@
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -96,56 +104,71 @@
// Create a copy so we can modify it.
List<SchemaTypeConfigProto> existingTypes =
new ArrayList<>(existingSchemaBuilder.getTypesList());
-
- SchemaProto newSchema =
- SchemaProto.newBuilder()
- .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Foo").build())
- .addTypes(
- SchemaTypeConfigProto.newBuilder()
- .setSchemaType("TestType")
- .addProperties(
- PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(
- PropertyConfigProto.DataType.Code
- .STRING)
- .setCardinality(
- PropertyConfigProto.Cardinality.Code
- .OPTIONAL)
- .setStringIndexingConfig(
- StringIndexingConfig.newBuilder()
- .setTokenizerType(
- StringIndexingConfig
- .TokenizerType
- .Code.PLAIN)
- .setTermMatchType(
- TermMatchType.Code
- .PREFIX)
- .build())
- .build())
- .addProperties(
- PropertyConfigProto.newBuilder()
- .setPropertyName("link")
- .setDataType(
- PropertyConfigProto.DataType.Code
- .DOCUMENT)
- .setCardinality(
- PropertyConfigProto.Cardinality.Code
- .OPTIONAL)
- .setSchemaType("RefType")
+ SchemaTypeConfigProto schemaTypeConfigProto1 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType("Foo").build();
+ SchemaTypeConfigProto schemaTypeConfigProto2 =
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("TestType")
+ .addProperties(
+ PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setCardinality(
+ PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setStringIndexingConfig(
+ StringIndexingConfig.newBuilder()
+ .setTokenizerType(
+ StringIndexingConfig.TokenizerType
+ .Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
.build())
.build())
+ .addProperties(
+ PropertyConfigProto.newBuilder()
+ .setPropertyName("link")
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setCardinality(
+ PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setSchemaType("RefType")
+ .build())
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto3 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType("RefType").build();
+ SchemaProto newSchema =
+ SchemaProto.newBuilder()
+ .addTypes(schemaTypeConfigProto1)
+ .addTypes(schemaTypeConfigProto2)
+ .addTypes(schemaTypeConfigProto3)
.build();
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "newDatabase"),
- existingSchemaBuilder,
- newSchema);
+ createPrefix("package", "newDatabase"), existingSchemaBuilder, newSchema);
// We rewrote all the new types that were added. And nothing was removed.
- assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
- .containsExactly("package$newDatabase/Foo", "package$newDatabase/TestType");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet())
+ .containsExactly(
+ "package$newDatabase/Foo",
+ "package$newDatabase/TestType",
+ "package$newDatabase/RefType");
+ assertThat(
+ rewrittenSchemaResults
+ .mRewrittenPrefixedTypes
+ .get("package$newDatabase/Foo")
+ .getSchemaType())
+ .isEqualTo("package$newDatabase/Foo");
+ assertThat(
+ rewrittenSchemaResults
+ .mRewrittenPrefixedTypes
+ .get("package$newDatabase/TestType")
+ .getSchemaType())
+ .isEqualTo("package$newDatabase/TestType");
+ assertThat(
+ rewrittenSchemaResults
+ .mRewrittenPrefixedTypes
+ .get("package$newDatabase/RefType")
+ .getSchemaType())
+ .isEqualTo("package$newDatabase/RefType");
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
SchemaProto expectedSchema =
@@ -190,6 +213,10 @@
"package$newDatabase/RefType")
.build())
.build())
+ .addTypes(
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$newDatabase/RefType")
+ .build())
.build();
existingTypes.addAll(expectedSchema.getTypesList());
@@ -216,12 +243,12 @@
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "existingDatabase"),
+ createPrefix("package", "existingDatabase"),
existingSchemaBuilder,
newSchema);
// Nothing was removed, but the method did rewrite the type name.
- assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet())
.containsExactly("package$existingDatabase/Foo");
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
@@ -251,14 +278,15 @@
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "existingDatabase"),
+ createPrefix("package", "existingDatabase"),
existingSchemaBuilder,
newSchema);
// Bar type was rewritten, but Foo ended up being deleted since it wasn't included in the
// new schema.
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
- .containsExactly("package$existingDatabase/Bar");
+ .containsKey("package$existingDatabase/Bar");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet().size()).isEqualTo(1);
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes)
.containsExactly("package$existingDatabase/Foo");
@@ -308,8 +336,7 @@
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
- mAppSearchImpl.addPrefixToDocument(
- actualDocument, AppSearchImpl.createPrefix("package", "databaseName"));
+ addPrefixToDocument(actualDocument, createPrefix("package", "databaseName"));
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
}
@@ -347,8 +374,7 @@
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
- assertThat(mAppSearchImpl.removePrefixesFromDocument(actualDocument))
- .isEqualTo("package$databaseName/");
+ assertThat(removePrefixesFromDocument(actualDocument)).isEqualTo("package$databaseName/");
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
}
@@ -365,8 +391,7 @@
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e =
expectThrows(
- AppSearchException.class,
- () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@@ -391,8 +416,7 @@
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e =
expectThrows(
- AppSearchException.class,
- () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@@ -484,7 +508,7 @@
// Rewrite SearchSpec
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
searchSpecProto,
- Collections.singleton(AppSearchImpl.createPrefix("package", "database")),
+ Collections.singleton(createPrefix("package", "database")),
ImmutableSet.of("package$database/type"));
assertThat(searchSpecProto.getSchemaTypeFiltersList())
.containsExactly("package$database/type");
@@ -531,8 +555,7 @@
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
searchSpecProto,
ImmutableSet.of(
- AppSearchImpl.createPrefix("package", "database1"),
- AppSearchImpl.createPrefix("package", "database2")),
+ createPrefix("package", "database1"), createPrefix("package", "database2")),
ImmutableSet.of(
"package$database1/typeA", "package$database1/typeB",
"package$database2/typeA", "package$database2/typeB"));
@@ -573,8 +596,7 @@
assertThat(
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
searchSpecProto,
- Collections.singleton(
- AppSearchImpl.createPrefix("package", "database")),
+ Collections.singleton(createPrefix("package", "database")),
/*allowedPrefixedSchemas=*/ Collections.emptySet()))
.isFalse();
}
@@ -1082,7 +1104,7 @@
// Has database1
Set<String> expectedPrefixes = new ArraySet<>(existingPrefixes);
- expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database1"));
+ expectedPrefixes.add(createPrefix("package", "database1"));
mAppSearchImpl.setSchema(
"package",
"database1",
@@ -1094,7 +1116,7 @@
assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes);
// Has both databases
- expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database2"));
+ expectedPrefixes.add(createPrefix("package", "database2"));
mAppSearchImpl.setSchema(
"package",
"database2",
@@ -1110,9 +1132,9 @@
public void testRewriteSearchResultProto() throws Exception {
final String prefix =
"com.package.foo"
- + AppSearchImpl.PACKAGE_DELIMITER
+ + PrefixUtil.PACKAGE_DELIMITER
+ "databaseName"
- + AppSearchImpl.DATABASE_DELIMITER;
+ + PrefixUtil.DATABASE_DELIMITER;
final String uri = "uri";
final String namespace = prefix + "namespace";
final String schemaType = prefix + "schema";
@@ -1128,18 +1150,22 @@
SearchResultProto.ResultProto.newBuilder().setDocument(documentProto).build();
SearchResultProto searchResultProto =
SearchResultProto.newBuilder().addResults(resultProto).build();
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(schemaType).build();
+ Map<String, Map<String, SchemaTypeConfigProto>> schemaMap =
+ ImmutableMap.of(prefix, ImmutableMap.of(schemaType, schemaTypeConfigProto));
DocumentProto.Builder strippedDocumentProto = documentProto.toBuilder();
- AppSearchImpl.removePrefixesFromDocument(strippedDocumentProto);
+ removePrefixesFromDocument(strippedDocumentProto);
SearchResultPage searchResultPage =
- AppSearchImpl.rewriteSearchResultProto(searchResultProto);
+ AppSearchImpl.rewriteSearchResultProto(searchResultProto, schemaMap);
for (SearchResult result : searchResultPage.getResults()) {
assertThat(result.getPackageName()).isEqualTo("com.package.foo");
assertThat(result.getDatabaseName()).isEqualTo("databaseName");
assertThat(result.getGenericDocument())
.isEqualTo(
GenericDocumentToProtoConverter.toGenericDocument(
- strippedDocumentProto.build()));
+ strippedDocumentProto.build(), prefix, schemaMap.get(prefix)));
}
}
@@ -1609,7 +1635,221 @@
expectThrows(
IllegalStateException.class,
() -> {
- appSearchImpl.persistToDisk();
+ appSearchImpl.persistToDisk(PersistType.Code.FULL);
});
}
+
+ @Test
+ public void testPutPersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ Context context = ApplicationProvider.getApplicationContext();
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Add a document and persist it.
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
+ appSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document);
+
+ // That document should be visible even from another instance.
+ AppSearchImpl appSearchImpl2 =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+ getResult =
+ appSearchImpl2.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document);
+ }
+
+ @Test
+ public void testDeletePersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ Context context = ApplicationProvider.getApplicationContext();
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Add two documents and persist them.
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
+ appSearchImpl.putDocument("package", "database", document1, /*logger=*/ null);
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace1", "uri2", "type").build();
+ appSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document1);
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Delete the first document
+ appSearchImpl.remove("package", "database", "namespace1", "uri1");
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Only the second document should be retrievable from another instance.
+ AppSearchImpl appSearchImpl2 =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl2.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl2.getDocument(
+ "package", "database", "namespace1", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+ }
+
+ @Test
+ public void testDeleteByQueryPersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ Context context = ApplicationProvider.getApplicationContext();
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Add two documents and persist them.
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
+ appSearchImpl.putDocument("package", "database", document1, /*logger=*/ null);
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace2", "uri2", "type").build();
+ appSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document1);
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace2", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Delete the first document
+ appSearchImpl.removeByQuery(
+ "package",
+ "database",
+ "",
+ new SearchSpec.Builder()
+ .addFilterNamespaces("namespace1")
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace2", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Only the second document should be retrievable from another instance.
+ AppSearchImpl appSearchImpl2 =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl2.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl2.getDocument(
+ "package", "database", "namespace2", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
index 70e1e05..63f031722 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
@@ -21,35 +21,50 @@
import android.app.appsearch.GenericDocument;
import com.android.server.appsearch.proto.DocumentProto;
+import com.android.server.appsearch.proto.PropertyConfigProto;
import com.android.server.appsearch.proto.PropertyProto;
+import com.android.server.appsearch.proto.SchemaTypeConfigProto;
import com.android.server.appsearch.protobuf.ByteString;
+import com.google.common.collect.ImmutableMap;
+
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class GenericDocumentToProtoConverterTest {
private static final byte[] BYTE_ARRAY_1 = new byte[] {(byte) 1, (byte) 2, (byte) 3};
private static final byte[] BYTE_ARRAY_2 = new byte[] {(byte) 4, (byte) 5, (byte) 6, (byte) 7};
+ private static final String SCHEMA_TYPE_1 = "sDocumentPropertiesSchemaType1";
+ private static final String SCHEMA_TYPE_2 = "sDocumentPropertiesSchemaType2";
private static final GenericDocument DOCUMENT_PROPERTIES_1 =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "namespace", "sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+ "namespace", "sDocumentProperties1", SCHEMA_TYPE_1)
.setCreationTimestampMillis(12345L)
.build();
private static final GenericDocument DOCUMENT_PROPERTIES_2 =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "namespace", "sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+ "namespace", "sDocumentProperties2", SCHEMA_TYPE_2)
.setCreationTimestampMillis(6789L)
.build();
+ private static final SchemaTypeConfigProto SCHEMA_PROTO_1 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(SCHEMA_TYPE_1).build();
+ private static final SchemaTypeConfigProto SCHEMA_PROTO_2 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(SCHEMA_TYPE_2).build();
+ private static final String PREFIX = "package$databaseName/";
+ private static final Map<String, SchemaTypeConfigProto> SCHEMA_MAP =
+ ImmutableMap.of(
+ PREFIX + SCHEMA_TYPE_1, SCHEMA_PROTO_1, PREFIX + SCHEMA_TYPE_2, SCHEMA_PROTO_2);
@Test
public void testDocumentProtoConvert() {
GenericDocument document =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "namespace", "uri1", "schemaType1")
+ "namespace", "uri1", SCHEMA_TYPE_1)
.setCreationTimestampMillis(5L)
.setScore(1)
.setTtlMillis(1L)
@@ -66,7 +81,7 @@
DocumentProto.Builder documentProtoBuilder =
DocumentProto.newBuilder()
.setUri("uri1")
- .setSchema("schemaType1")
+ .setSchema(SCHEMA_TYPE_1)
.setCreationTimestampMs(5L)
.setScore(1)
.setTtlMs(1L)
@@ -109,9 +124,133 @@
documentProtoBuilder.addProperties(propertyProtoMap.get(key));
}
DocumentProto documentProto = documentProtoBuilder.build();
- assertThat(GenericDocumentToProtoConverter.toDocumentProto(document))
- .isEqualTo(documentProto);
- assertThat(document)
- .isEqualTo(GenericDocumentToProtoConverter.toGenericDocument(documentProto));
+
+ GenericDocument convertedGenericDocument =
+ GenericDocumentToProtoConverter.toGenericDocument(
+ documentProto, PREFIX, SCHEMA_MAP);
+ DocumentProto convertedDocumentProto =
+ GenericDocumentToProtoConverter.toDocumentProto(document);
+
+ assertThat(convertedDocumentProto).isEqualTo(documentProto);
+ assertThat(convertedGenericDocument).isEqualTo(document);
+ }
+
+ @Test
+ public void testConvertDocument_whenPropertyHasEmptyList() {
+ String emptyStringPropertyName = "emptyStringProperty";
+ DocumentProto documentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri1")
+ .setSchema(SCHEMA_TYPE_1)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder().setName(emptyStringPropertyName).build())
+ .build();
+
+ PropertyConfigProto emptyStringListProperty =
+ PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setPropertyName(emptyStringPropertyName)
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder()
+ .addProperties(emptyStringListProperty)
+ .setSchemaType(SCHEMA_TYPE_1)
+ .build();
+ Map<String, SchemaTypeConfigProto> schemaMap =
+ ImmutableMap.of(PREFIX + SCHEMA_TYPE_1, schemaTypeConfigProto);
+
+ GenericDocument convertedDocument =
+ GenericDocumentToProtoConverter.toGenericDocument(documentProto, PREFIX, schemaMap);
+
+ GenericDocument expectedDocument =
+ new GenericDocument.Builder<GenericDocument.Builder<?>>(
+ "namespace", "uri1", SCHEMA_TYPE_1)
+ .setCreationTimestampMillis(5L)
+ .setPropertyString(emptyStringPropertyName)
+ .build();
+ assertThat(convertedDocument).isEqualTo(expectedDocument);
+ assertThat(expectedDocument.getPropertyStringArray(emptyStringPropertyName)).isEmpty();
+ }
+
+ @Test
+ public void testConvertDocument_whenNestedDocumentPropertyHasEmptyList() {
+ String emptyStringPropertyName = "emptyStringProperty";
+ String documentPropertyName = "documentProperty";
+ DocumentProto nestedDocumentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri2")
+ .setSchema(SCHEMA_TYPE_2)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder().setName(emptyStringPropertyName).build())
+ .build();
+ DocumentProto documentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri1")
+ .setSchema(SCHEMA_TYPE_1)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder()
+ .addDocumentValues(nestedDocumentProto)
+ .setName(documentPropertyName)
+ .build())
+ .build();
+
+ PropertyConfigProto documentProperty =
+ PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setPropertyName(documentPropertyName)
+ .setSchemaType(SCHEMA_TYPE_2)
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder()
+ .addProperties(documentProperty)
+ .setSchemaType(SCHEMA_TYPE_1)
+ .build();
+ PropertyConfigProto emptyStringListProperty =
+ PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setPropertyName(emptyStringPropertyName)
+ .build();
+ SchemaTypeConfigProto nestedSchemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder()
+ .addProperties(emptyStringListProperty)
+ .setSchemaType(SCHEMA_TYPE_2)
+ .build();
+ Map<String, SchemaTypeConfigProto> schemaMap =
+ ImmutableMap.of(
+ PREFIX + SCHEMA_TYPE_1,
+ schemaTypeConfigProto,
+ PREFIX + SCHEMA_TYPE_2,
+ nestedSchemaTypeConfigProto);
+
+ GenericDocument convertedDocument =
+ GenericDocumentToProtoConverter.toGenericDocument(documentProto, PREFIX, schemaMap);
+
+ GenericDocument expectedDocument =
+ new GenericDocument.Builder<GenericDocument.Builder<?>>(
+ "namespace", "uri1", SCHEMA_TYPE_1)
+ .setCreationTimestampMillis(5L)
+ .setPropertyDocument(
+ documentPropertyName,
+ new GenericDocument.Builder<GenericDocument.Builder<?>>(
+ "namespace", "uri2", SCHEMA_TYPE_2)
+ .setCreationTimestampMillis(5L)
+ .setPropertyString(emptyStringPropertyName)
+ .build())
+ .build();
+ assertThat(convertedDocument).isEqualTo(expectedDocument);
+ assertThat(
+ expectedDocument
+ .getPropertyDocument(documentPropertyName)
+ .getPropertyStringArray(emptyStringPropertyName))
+ .isEmpty();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index d07211f..26fac49 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -21,8 +21,10 @@
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultPage;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.proto.DocumentProto;
import com.android.server.appsearch.proto.PropertyProto;
+import com.android.server.appsearch.proto.SchemaTypeConfigProto;
import com.android.server.appsearch.proto.SearchResultProto;
import com.android.server.appsearch.proto.SnippetMatchProto;
import com.android.server.appsearch.proto.SnippetProto;
@@ -30,20 +32,29 @@
import org.junit.Test;
import java.util.Collections;
+import java.util.Map;
public class SnippetTest {
+ private static final String SCHEMA_TYPE = "schema1";
+ private static final String PACKAGE_NAME = "packageName";
+ private static final String DATABASE_NAME = "databaseName";
+ private static final String PREFIX = PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
+ private static final SchemaTypeConfigProto SCHEMA_TYPE_CONFIG_PROTO =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(PREFIX + SCHEMA_TYPE).build();
+ private static final Map<String, Map<String, SchemaTypeConfigProto>> SCHEMA_MAP =
+ Collections.singletonMap(
+ PREFIX,
+ Collections.singletonMap(PREFIX + SCHEMA_TYPE, SCHEMA_TYPE_CONFIG_PROTO));
// TODO(tytytyww): Add tests for Double and Long Snippets.
@Test
public void testSingleStringSnippet() {
-
final String propertyKeyString = "content";
final String propertyValueString =
"A commonly used fake word is foo.\n"
+ " Another nonsense word that’s used a lot\n"
+ " is bar.\n";
final String uri = "uri1";
- final String schemaType = "schema1";
final String searchWord = "foo";
final String exactMatch = "foo";
final String window = "is foo";
@@ -57,7 +68,7 @@
DocumentProto documentProto =
DocumentProto.newBuilder()
.setUri(uri)
- .setSchema(schemaType)
+ .setSchema(SCHEMA_TYPE)
.addProperties(property)
.build();
SnippetProto snippetProto =
@@ -86,8 +97,9 @@
SearchResultPage searchResultPage =
SearchResultToProtoConverter.toSearchResultPage(
searchResultProto,
- Collections.singletonList("packageName"),
- Collections.singletonList("databaseName"));
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
for (SearchResult result : searchResultPage.getResults()) {
SearchResult.MatchInfo match = result.getMatches().get(0);
assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
@@ -112,7 +124,6 @@
+ " Another nonsense word that’s used a lot\n"
+ " is bar.\n";
final String uri = "uri1";
- final String schemaType = "schema1";
final String searchWord = "foo";
final String exactMatch = "foo";
final String window = "is foo";
@@ -126,7 +137,7 @@
DocumentProto documentProto =
DocumentProto.newBuilder()
.setUri(uri)
- .setSchema(schemaType)
+ .setSchema(SCHEMA_TYPE)
.addProperties(property)
.build();
SearchResultProto.ResultProto resultProto =
@@ -137,8 +148,9 @@
SearchResultPage searchResultPage =
SearchResultToProtoConverter.toSearchResultPage(
searchResultProto,
- Collections.singletonList("packageName"),
- Collections.singletonList("databaseName"));
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
for (SearchResult result : searchResultPage.getResults()) {
assertThat(result.getMatches()).isEmpty();
}
@@ -162,7 +174,7 @@
DocumentProto documentProto =
DocumentProto.newBuilder()
.setUri("uri1")
- .setSchema("schema1")
+ .setSchema(SCHEMA_TYPE)
.addProperties(property1)
.addProperties(property2)
.build();
@@ -203,8 +215,9 @@
SearchResultPage searchResultPage =
SearchResultToProtoConverter.toSearchResultPage(
searchResultProto,
- Collections.singletonList("packageName"),
- Collections.singletonList("databaseName"));
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
for (SearchResult result : searchResultPage.getResults()) {
SearchResult.MatchInfo match1 = result.getMatches().get(0);
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index 79a5ed6..5c53d43 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -98,8 +98,9 @@
Log.i(TAG, "starting testPostA2dpDeviceConnectionChange");
Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
- mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
+ mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS);
verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState(
any(BluetoothDevice.class),
@@ -209,20 +210,23 @@
((NoOpAudioSystemAdapter) mSpyAudioSystem).configureIsStreamActive(mockMediaPlayback);
// first connection: ensure the device is connected as a starting condition for the test
- mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
+ mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
// disconnection
- mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
- BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1);
+ mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
+ BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1));
if (delayAfterDisconnection > 0) {
Thread.sleep(delayAfterDisconnection);
}
// reconnection
- mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2);
+ mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2));
Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS);
// Verify disconnection has been cancelled and we're seeing two connections attempts,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index e322ce5..96bab61 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -308,6 +308,8 @@
componentInfo,
type,
false /* resetLockoutRequiresHardwareAuthToken */));
+
+ when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
}
private void setupFace(int id, boolean confirmationAlwaysRequired,
@@ -329,6 +331,6 @@
}
});
- when(mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index a5fbab5..ec3bea3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -378,7 +378,7 @@
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
// Disabled in user settings receives onError
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
waitForIdle();
@@ -389,7 +389,7 @@
// Enrolled, not disabled in settings, user requires confirmation in settings
resetReceivers();
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
when(mBiometricService.mSettingObserver.getConfirmationAlwaysRequired(
anyInt() /* modality */, anyInt() /* userId */))
.thenReturn(true);
@@ -1197,7 +1197,7 @@
@Test
public void testCanAuthenticate_whenBiometricsNotEnabledForApps() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
// When only biometric is requested
@@ -1322,6 +1322,8 @@
final int testId = 0;
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
+
when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any()))
.thenReturn(true);
when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
@@ -1536,7 +1538,7 @@
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
if ((modality & BiometricAuthenticator.TYPE_FINGERPRINT) != 0) {
when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any()))
@@ -1564,7 +1566,7 @@
mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
- when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
+ when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
assertEquals(modalities.length, strengths.length);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 78e2dee..89798ce 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -31,7 +31,7 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
-import static android.app.admin.PasswordMetrics.computeForPassword;
+import static android.app.admin.PasswordMetrics.computeForPasswordOrPin;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
import static android.net.InetAddresses.parseNumericAddress;
@@ -1304,6 +1304,16 @@
@Test
public void testSetDeviceOwner_failures() throws Exception {
// TODO Test more failure cases. Basically test all chacks in enforceCanSetDeviceOwner().
+ // Package doesn't exist and caller is not system
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ "Calling identity is not authorized",
+ () -> dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
+
+ // Package exists, but caller is not system
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ "Calling identity is not authorized",
+ () -> dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
}
@Test
@@ -1541,6 +1551,16 @@
@Test
public void testSetProfileOwner_failures() throws Exception {
// TODO Test more failure cases. Basically test all chacks in enforceCanSetProfileOwner().
+ // Package doesn't exist and caller is not system
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ "Calling identity is not authorized",
+ () -> dpm.setProfileOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
+
+ // Package exists, but caller is not system
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ "Calling identity is not authorized",
+ () -> dpm.setProfileOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
}
@Test
@@ -5146,7 +5166,8 @@
reset(mContext.spiedContext);
- PasswordMetrics passwordMetricsNoSymbols = computeForPassword("abcdXYZ5".getBytes());
+ PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin(
+ "abcdXYZ5".getBytes(), /* isPin */ false);
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.isActivePasswordSufficient()).isTrue();
@@ -5173,7 +5194,8 @@
reset(mContext.spiedContext);
assertThat(dpm.isActivePasswordSufficient()).isFalse();
- PasswordMetrics passwordMetricsWithSymbols = computeForPassword("abcd.XY5".getBytes());
+ PasswordMetrics passwordMetricsWithSymbols = computeForPasswordOrPin(
+ "abcd.XY5".getBytes(), /* isPin */ false);
setActivePasswordState(passwordMetricsWithSymbols);
assertThat(dpm.isActivePasswordSufficient()).isTrue();
@@ -5227,7 +5249,7 @@
parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPassword("184342".getBytes()));
+ .thenReturn(computeForPasswordOrPin("184342".getBytes(), /* isPin */ true));
// Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly
// on the parent admin)
@@ -6350,7 +6372,7 @@
.thenReturn(CALLER_USER_HANDLE);
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(CALLER_USER_HANDLE))
- .thenReturn(computeForPassword("asdf".getBytes()));
+ .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false));
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
}
@@ -6370,10 +6392,10 @@
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(CALLER_USER_HANDLE))
- .thenReturn(computeForPassword("asdf".getBytes()));
+ .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false));
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(parentUser.id))
- .thenReturn(computeForPassword("parentUser".getBytes()));
+ .thenReturn(computeForPasswordOrPin("parentUser".getBytes(), /* isPin */ false));
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
}
@@ -7049,13 +7071,15 @@
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
reset(mContext.spiedContext);
- PasswordMetrics passwordMetricsNoSymbols = computeForPassword("1234".getBytes());
+ PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin(
+ "1234".getBytes(), /* isPin */ true);
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_LOW);
assertThat(dpm.isActivePasswordSufficient()).isFalse();
reset(mContext.spiedContext);
- passwordMetricsNoSymbols = computeForPassword("84125312943a".getBytes());
+ passwordMetricsNoSymbols = computeForPasswordOrPin(
+ "84125312943a".getBytes(), /* isPin */ false);
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
// using isActivePasswordSufficient
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 39e06a3..950b8a2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -25,6 +25,13 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
@@ -494,4 +501,99 @@
ABORT_UNRECOGNIZED_OPCODE);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort);
}
+
+ @Test
+ public void handleReportAudioStatus_SamOnArcOff_setStreamVolumeNotCalled() {
+ // Emulate Audio device on port 0x1000 (does not support ARC)
+ mNativeWrapper.setPortConnectionStatus(1, true);
+ HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(hdmiCecMessage);
+
+ HdmiCecFeatureAction systemAudioAutoInitiationAction =
+ new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
+ HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ mHdmiControlService.handleCecCommand(reportSystemAudioMode);
+
+ mTestLooper.dispatchAll();
+
+ // SAM must be on; ARC must be off
+ assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
+ assertFalse(mHdmiCecLocalDeviceTv.isArcEstablished());
+
+ HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ 50, // Volume of incoming message does not affect HDMI-CEC logic
+ false);
+ mNativeWrapper.onCecMessage(reportAudioStatus);
+
+ mTestLooper.dispatchAll();
+
+ verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void handleReportAudioStatus_SamOnArcOn_setStreamVolumeCalled() {
+ mNativeWrapper.setPortConnectionStatus(2, true);
+ HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(hdmiCecMessage);
+
+ HdmiCecFeatureAction systemAudioAutoInitiationAction =
+ new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
+ mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
+
+ HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode(
+ ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true);
+ mHdmiControlService.handleCecCommand(reportSystemAudioMode);
+
+ HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV);
+ mNativeWrapper.onCecMessage(requestArcInitiation);
+
+ mTestLooper.dispatchAll();
+
+ // SAM and ARC must be on
+ assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
+ assertTrue(mHdmiCecLocalDeviceTv.isArcEstablished());
+
+ HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ 50, // Volume of incoming message does not affect HDMI-CEC logic
+ false);
+ mNativeWrapper.onCecMessage(reportAudioStatus);
+
+ mTestLooper.dispatchAll();
+
+ verify(mAudioManager, times(1)).setStreamVolume(anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void handleReportAudioStatus_SamOff_setStreamVolumeNotCalled() {
+ // Emulate Audio device on port 0x1000 (does not support ARC)
+ mNativeWrapper.setPortConnectionStatus(1, true);
+ HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(hdmiCecMessage);
+
+ mTestLooper.dispatchAll();
+
+ assertFalse(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
+
+ HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV,
+ 50, // Volume of incoming message does not affect HDMI-CEC logic
+ false);
+ mNativeWrapper.onCecMessage(reportAudioStatus);
+
+ mTestLooper.dispatchAll();
+
+ verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index 691d174..f2bb1d6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -87,6 +87,11 @@
}
@Override
+ String getRebootEscrowFile(int userId) {
+ return makeDirs(mStorageDir, super.getRebootEscrowFile(userId)).getAbsolutePath();
+ }
+
+ @Override
protected File getSyntheticPasswordDirectoryForUser(int userId) {
return makeDirs(mStorageDir, super.getSyntheticPasswordDirectoryForUser(
userId).getAbsolutePath());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 8c08226..49a54ec 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -21,6 +21,11 @@
import static android.content.pm.UserInfo.FLAG_PROFILE;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -327,7 +332,7 @@
assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
assertNotNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
verify(mRebootEscrow).storeKey(any());
@@ -351,7 +356,7 @@
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -373,7 +378,7 @@
assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
doThrow(ServiceSpecificException.class).when(mRebootEscrow).storeKey(any());
- assertFalse(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_STORE_ESCROW_KEY, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(any());
}
@@ -396,7 +401,7 @@
assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
assertNotNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
verify(mRebootEscrow, times(1)).storeKey(any());
@@ -408,15 +413,24 @@
@Test
public void armService_NoInitialization_Failure() throws Exception {
- assertFalse(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_ESCROW_NOT_READY, mService.armRebootEscrowIfNeeded());
verifyNoMoreInteractions(mRebootEscrow);
}
@Test
public void armService_RebootEscrowServiceException_Failure() throws Exception {
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mRebootEscrow);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mRebootEscrow, never()).storeKey(any());
+
doThrow(RemoteException.class).when(mRebootEscrow).storeKey(any());
- assertFalse(mService.armRebootEscrowIfNeeded());
- verifyNoMoreInteractions(mRebootEscrow);
+ assertEquals(ARM_REBOOT_ERROR_STORE_ESCROW_KEY, mService.armRebootEscrowIfNeeded());
+ verify(mRebootEscrow).storeKey(any());
}
@Test
@@ -439,7 +453,7 @@
verify(mRebootEscrow, never()).storeKey(any());
ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
verify(mKeyStoreManager).getKeyStoreEncryptionKey();
@@ -483,7 +497,7 @@
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -520,7 +534,7 @@
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -557,7 +571,7 @@
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -597,7 +611,7 @@
// Use x -> x for both wrap & unwrap functions.
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
assertTrue(mStorage.hasRebootEscrowServerBlob());
@@ -635,7 +649,7 @@
verify(mRebootEscrow, never()).storeKey(any());
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(any());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -695,7 +709,7 @@
verify(mRebootEscrow, never()).storeKey(any());
ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -732,8 +746,7 @@
verify(mockListener).onPreparedForReboot(eq(true));
verify(mRebootEscrow, never()).storeKey(any());
-
- assertTrue(mService.armRebootEscrowIfNeeded());
+ assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
verify(mRebootEscrow).storeKey(any());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -756,4 +769,28 @@
assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
metricsErrorCodeCaptor.getValue());
}
+
+ @Test
+ public void armServiceProviderMismatch_Failure() throws Exception {
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mRebootEscrow);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+ verify(mRebootEscrow, never()).storeKey(any());
+
+ assertNull(
+ mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
+ // Change the provider to server based, expect the reboot to fail
+ when(mInjected.forceServerBased()).thenReturn(true);
+ assertEquals(ARM_REBOOT_ERROR_PROVIDER_MISMATCH, mService.armRebootEscrowIfNeeded());
+ assertNull(
+ mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
+ // Verify that the escrow key & data have been cleared.
+ verify(mRebootEscrow).storeKey(eq(new byte[32]));
+ assertFalse(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
index d888b92..876c845 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -37,7 +37,7 @@
@JvmStatic
@Parameterized.Parameters(name = "deferRebuild {0}")
- fun parameters() = arrayOf(true, false)
+ fun parameters() = arrayOf(/*true, */false)
}
private lateinit var mapper: OverlayReferenceMapper
@@ -55,11 +55,17 @@
fun targetWithOverlay() {
val target = mockTarget()
val overlay = mockOverlay()
- val existing = mapper.addInOrder(overlay)
+ val existing = mapper.addInOrder(overlay) {
+ assertThat(it).isEmpty()
+ }
assertEmpty()
- mapper.addInOrder(target, existing = existing)
+ mapper.addInOrder(target, existing = existing) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay))
- mapper.remove(target)
+ mapper.remove(target) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertEmpty()
}
@@ -78,22 +84,34 @@
)
)
)
- val existing = mapper.addInOrder(overlay0, overlay1)
+ val existing = mapper.addInOrder(overlay0, overlay1) {
+ assertThat(it).isEmpty()
+ }
assertEmpty()
- mapper.addInOrder(target, existing = existing)
+ mapper.addInOrder(target, existing = existing) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay0, overlay1))
- mapper.remove(overlay0)
+ mapper.remove(overlay0) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay1))
- mapper.remove(target)
+ mapper.remove(target) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertEmpty()
}
@Test
fun targetWithoutOverlay() {
val target = mockTarget()
- mapper.addInOrder(target)
+ mapper.addInOrder(target) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
- mapper.remove(target)
+ mapper.remove(target) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertEmpty()
}
@@ -101,11 +119,17 @@
fun overlayWithTarget() {
val target = mockTarget()
val overlay = mockOverlay()
- val existing = mapper.addInOrder(target)
+ val existing = mapper.addInOrder(target) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
- mapper.addInOrder(overlay, existing = existing)
+ mapper.addInOrder(overlay, existing = existing) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay))
- mapper.remove(overlay)
+ mapper.remove(overlay) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
}
@@ -122,34 +146,52 @@
)
)
)
- mapper.addInOrder(target0, target1, overlay)
+ mapper.addInOrder(target0, target1, overlay) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target0, target1, overlay))
- mapper.remove(target0)
+ mapper.remove(target0) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertMapping(ACTOR_PACKAGE_NAME to setOf(target1, overlay))
- mapper.remove(target1)
+ mapper.remove(target1) {
+ assertThat(it).containsExactly(ACTOR_PACKAGE_NAME)
+ }
assertEmpty()
}
@Test
fun overlayWithoutTarget() {
val overlay = mockOverlay()
- mapper.addInOrder(overlay)
+ mapper.addInOrder(overlay) {
+ assertThat(it).isEmpty()
+ }
// An overlay can only have visibility exposed through its target
assertEmpty()
- mapper.remove(overlay)
+ mapper.remove(overlay) {
+ assertThat(it).isEmpty()
+ }
assertEmpty()
}
private fun OverlayReferenceMapper.addInOrder(
vararg pkgs: AndroidPackage,
- existing: MutableMap<String, AndroidPackage> = mutableMapOf()
- ) = pkgs.fold(existing) { map, pkg ->
- addPkg(pkg, map)
- map[pkg.packageName] = pkg
- return@fold map
+ existing: MutableMap<String, AndroidPackage> = mutableMapOf(),
+ assertion: (changedPackages: Set<String>) -> Unit
+ ): MutableMap<String, AndroidPackage> {
+ val changedPackages = mutableSetOf<String>()
+ pkgs.forEach {
+ changedPackages += addPkg(it, existing)
+ existing[it.packageName] = it
+ }
+ assertion(changedPackages)
+ return existing
}
- private fun OverlayReferenceMapper.remove(pkg: AndroidPackage) = removePkg(pkg.packageName)
+ private fun OverlayReferenceMapper.remove(
+ pkg: AndroidPackage,
+ assertion: (changedPackages: Set<String>) -> Unit
+ ) = assertion(removePkg(pkg.packageName))
private fun assertMapping(vararg pairs: Pair<String, Set<AndroidPackage>>) {
val expected = pairs.associate { it }
diff --git a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
index 8070bd1..558e259 100644
--- a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
@@ -7,6 +7,14 @@
"include-filter": "com.android.server.om."
}
]
+ },
+ {
+ "name": "PackageManagerServiceHostTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm.test.OverlayActorVisibilityTest"
+ }
+ ]
}
]
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 9f428c7..67dd055 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -799,10 +799,18 @@
simulateAddBasicAndroid(appsFilter);
appsFilter.onSystemReady();
- PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID);
+ // Packages must be added in actor -> overlay -> target order so that the implicit
+ // visibility of the actor into the overlay can be tested
+
+ PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_APPID);
PackageSetting overlaySetting =
simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID);
- PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_APPID);
+
+ // Actor can not see overlay (yet)
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
+ overlaySetting, SYSTEM_USER));
+
+ PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID);
// Actor can see both target and overlay
assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
@@ -821,6 +829,12 @@
actorSetting, SYSTEM_USER));
assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
actorSetting, SYSTEM_USER));
+
+ appsFilter.removePackage(targetSetting);
+
+ // Actor loses visibility to the overlay via removal of the target
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
+ overlaySetting, SYSTEM_USER));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java b/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java
new file mode 100644
index 0000000..153938c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/WatchedIntentHandlingTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.IntentFilter;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.utils.WatchableTester;
+
+import org.junit.Test;
+
+import java.util.Iterator;
+
+@SmallTest
+public class WatchedIntentHandlingTest {
+
+ @Test
+ public void testWatchedIntentFilter() {
+ IntentFilter i = new IntentFilter("TEST_ACTION");
+ WatchedIntentFilter f = new WatchedIntentFilter(i);
+ final WatchableTester watcher =
+ new WatchableTester(f, "WatchedIntentFilter");
+ watcher.register();
+ int wantPriority = 3;
+ f.setPriority(wantPriority);
+ watcher.verifyChangeReported("setPriority");
+ f.getPriority();
+ watcher.verifyNoChangeReported("getPriority");
+ assertTrue(f.getPriority() == wantPriority);
+ f.setPriority(f.getPriority() + 1);
+ watcher.verifyChangeReported("setPriority");
+ assertTrue(f.getPriority() == wantPriority + 1);
+
+ i.setPriority(wantPriority + 3);
+ watcher.verifyNoChangeReported("indendent intent");
+ assertTrue(f.getPriority() == wantPriority + 1);
+
+ f.addAction("action-1");
+ f.addAction("action-2");
+ f.addAction("action-3");
+ f.addAction("action-4");
+ watcher.verifyChangeReported("addAction");
+ int actionCount = f.countActions();
+
+ Iterator<String> actions = f.actionsIterator();
+ watcher.verifyNoChangeReported("actionsIterator 1");
+ int count = 0;
+ while (actions.hasNext()) {
+ assertTrue(f.hasAction(actions.next()));
+ count++;
+ }
+ watcher.verifyNoChangeReported("actionsIterator 2");
+ assertTrue(count == actionCount);
+
+ actions = f.actionsIterator();
+ watcher.verifyNoChangeReported("actionsIterator 1");
+ while (actions.hasNext()) {
+ if (actions.next().equals("action-3")) {
+ actions.remove();
+ watcher.verifyChangeReported("remove action");
+ }
+ }
+ assertTrue(f.countActions() == actionCount - 1);
+
+ WatchedIntentFilter s1 = f.snapshot();
+ watcher.verifyNoChangeReported("pulled snapshot");
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index 2b358ea..b64810b 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -18,11 +18,14 @@
import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME;
import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED;
+import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE;
import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -31,6 +34,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -91,7 +95,8 @@
mUncryptUpdateFileWriter = mock(FileWriter.class);
mLockSettingsInternal = mock(LockSettingsInternal.class);
- when(mLockSettingsInternal.armRebootEscrow()).thenReturn(true);
+ doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_NONE).when(mLockSettingsInternal)
+ .armRebootEscrow();
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
mIPowerManager = mock(IPowerManager.class);
@@ -489,4 +494,27 @@
}
// TODO(xunchang) add more multi client tests
+
+ @Test
+ public void rebootWithLskf_armEscrowDataFatalError_Failure() throws Exception {
+ doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH)
+ .when(mLockSettingsInternal).armRebootEscrow();
+
+ assertTrue(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null));
+ mRecoverySystemService.onPreparedForReboot(true);
+ assertTrue(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
+
+ when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
+ + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(1);
+ when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
+ anyInt())).thenReturn(1);
+ assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE,
+ mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true));
+ // Verify that the RoR preparation state has been cleared.
+ assertFalse(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
+ verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(5004 /* provider mismatch */),
+ eq(1000), eq(1) /* client count */, eq(1) /* request count */,
+ eq(true) /* slot switch */, anyBoolean(), anyInt(),
+ eq(1) /* lskf capture count */);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 742f503..32fed3b 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -248,21 +248,6 @@
mStubbedTimeDetectorStrategy.verifyDumpCalled();
}
- @Test
- public void testAutoTimeDetectionToggle() throws Exception {
- mTimeDetectorService.handleAutoTimeDetectionChanged();
- mTestHandler.assertTotalMessagesEnqueued(1);
- mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionChangedCalled();
-
- mStubbedTimeDetectorStrategy.resetCallTracking();
-
- mTimeDetectorService.handleAutoTimeDetectionChanged();
- mTestHandler.assertTotalMessagesEnqueued(2);
- mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionChangedCalled();
- }
-
private static TelephonyTimeSuggestion createTelephonyTimeSuggestion() {
int slotIndex = 1234;
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
@@ -298,7 +283,6 @@
private NetworkTimeSuggestion mLastNetworkSuggestion;
private GnssTimeSuggestion mLastGnssSuggestion;
private ExternalTimeSuggestion mLastExternalSuggestion;
- private boolean mHandleAutoTimeDetectionChangedCalled;
private boolean mDumpCalled;
@Override
@@ -333,11 +317,6 @@
}
@Override
- public void handleAutoTimeConfigChanged() {
- mHandleAutoTimeDetectionChangedCalled = true;
- }
-
- @Override
public void dump(IndentingPrintWriter pw, String[] args) {
mDumpCalled = true;
}
@@ -348,7 +327,6 @@
mLastNetworkSuggestion = null;
mLastGnssSuggestion = null;
mLastExternalSuggestion = null;
- mHandleAutoTimeDetectionChangedCalled = false;
mDumpCalled = false;
}
@@ -372,10 +350,6 @@
assertEquals(expectedSuggestion, mLastExternalSuggestion);
}
- void verifyHandleAutoTimeDetectionChangedCalled() {
- assertTrue(mHandleAutoTimeDetectionChangedCalled);
- }
-
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 095703e..0d5b5a5 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -37,6 +37,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +47,7 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
+import java.util.Objects;
@RunWith(AndroidJUnit4.class)
public class TimeDetectorStrategyImplTest {
@@ -1133,11 +1135,17 @@
private long mSystemClockMillis;
private int mSystemClockUpdateThresholdMillis = 2000;
private int[] mAutoOriginPriorities = PROVIDERS_PRIORITY;
+ private ConfigurationChangeListener mConfigChangeListener;
// Tracking operations.
private boolean mSystemClockWasSet;
@Override
+ public void setConfigChangeListener(ConfigurationChangeListener listener) {
+ mConfigChangeListener = Objects.requireNonNull(listener);
+ }
+
+ @Override
public int systemClockUpdateThresholdMillis() {
return mSystemClockUpdateThresholdMillis;
}
@@ -1230,6 +1238,7 @@
void simulateAutoTimeZoneDetectionToggle() {
mAutoTimeDetectionEnabled = !mAutoTimeDetectionEnabled;
+ mConfigChangeListener.onChange();
}
void verifySystemClockNotSet() {
@@ -1330,7 +1339,6 @@
Script simulateAutoTimeDetectionToggle() {
mFakeEnvironment.simulateAutoTimeZoneDetectionToggle();
- mTimeDetectorStrategy.handleAutoTimeConfigChanged();
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 57e95d7..f255c67 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -896,4 +896,25 @@
leafD.tick();
tester.verify(3, "tick leafD");
}
+
+ @Test
+ public void testSnapshotCache() {
+ final String name = "SnapshotCache";
+ WatchableTester tester;
+
+ Leaf leafA = new Leaf();
+ SnapshotCache<Leaf> cache = new SnapshotCache<>(leafA, leafA) {
+ @Override
+ public Leaf createSnapshot() {
+ return mSource.snapshot();
+ }};
+
+ Leaf s1 = cache.snapshot();
+ assertTrue(s1 == cache.snapshot());
+ leafA.tick();
+ Leaf s2 = cache.snapshot();
+ assertTrue(s1 != s2);
+ assertTrue(leafA.get() == s1.get() + 1);
+ assertTrue(leafA.get() == s2.get());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java
new file mode 100644
index 0000000..2f5a5cc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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.uwb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.platform.test.annotations.Presubmit;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.uwb.IUwbAdapter;
+import android.uwb.IUwbAdapterStateCallbacks;
+import android.uwb.IUwbRangingCallbacks;
+import android.uwb.RangingReport;
+import android.uwb.RangingSession;
+import android.uwb.SessionHandle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link UwbServiceImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class UwbServiceImplTest {
+ @Mock private IUwbAdapter mVendorService;
+ @Mock private IBinder mVendorServiceBinder;
+ @Mock private Context mContext;
+ @Mock private UwbInjector mUwbInjector;
+ @Captor private ArgumentCaptor<IUwbRangingCallbacks> mRangingCbCaptor;
+ @Captor private ArgumentCaptor<IBinder.DeathRecipient> mClientDeathCaptor;
+ @Captor private ArgumentCaptor<IBinder.DeathRecipient> mVendorServiceDeathCaptor;
+
+ private UwbServiceImpl mUwbServiceImpl;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mUwbInjector.getVendorService()).thenReturn(mVendorService);
+ when(mVendorService.asBinder()).thenReturn(mVendorServiceBinder);
+ mUwbServiceImpl = new UwbServiceImpl(mContext, mUwbInjector);
+ }
+
+ @Test
+ public void testApiCallThrowsIllegalStateExceptionIfVendorServiceNotFound() throws Exception {
+ when(mUwbInjector.getVendorService()).thenReturn(null);
+
+ final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
+ try {
+ mUwbServiceImpl.registerAdapterStateCallbacks(cb);
+ fail();
+ } catch (IllegalStateException e) { /* pass */ }
+ }
+
+ @Test
+ public void testRegisterAdapterStateCallbacks() throws Exception {
+ final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
+ mUwbServiceImpl.registerAdapterStateCallbacks(cb);
+
+ verify(mVendorService).registerAdapterStateCallbacks(cb);
+ }
+
+ @Test
+ public void testUnregisterAdapterStateCallbacks() throws Exception {
+ final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class);
+ mUwbServiceImpl.unregisterAdapterStateCallbacks(cb);
+
+ verify(mVendorService).unregisterAdapterStateCallbacks(cb);
+ }
+
+ @Test
+ public void testGetTimestampResolutionNanos() throws Exception {
+ final long timestamp = 34L;
+ when(mVendorService.getTimestampResolutionNanos()).thenReturn(timestamp);
+ assertThat(mUwbServiceImpl.getTimestampResolutionNanos()).isEqualTo(timestamp);
+
+ verify(mVendorService).getTimestampResolutionNanos();
+ }
+
+ @Test
+ public void testGetSpecificationInfo() throws Exception {
+ final PersistableBundle specification = new PersistableBundle();
+ when(mVendorService.getSpecificationInfo()).thenReturn(specification);
+ assertThat(mUwbServiceImpl.getSpecificationInfo()).isEqualTo(specification);
+
+ verify(mVendorService).getSpecificationInfo();
+ }
+
+ @Test
+ public void testOpenRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+ }
+
+ @Test
+ public void testStartRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final PersistableBundle parameters = new PersistableBundle();
+
+ mUwbServiceImpl.startRanging(sessionHandle, parameters);
+
+ verify(mVendorService).startRanging(sessionHandle, parameters);
+ }
+
+ @Test
+ public void testReconfigureRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final PersistableBundle parameters = new PersistableBundle();
+
+ mUwbServiceImpl.reconfigureRanging(sessionHandle, parameters);
+
+ verify(mVendorService).reconfigureRanging(sessionHandle, parameters);
+ }
+
+ @Test
+ public void testStopRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+
+ mUwbServiceImpl.stopRanging(sessionHandle);
+
+ verify(mVendorService).stopRanging(sessionHandle);
+ }
+
+ @Test
+ public void testCloseRanging() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+
+ mUwbServiceImpl.closeRanging(sessionHandle);
+
+ verify(mVendorService).closeRanging(sessionHandle);
+ }
+
+ @Test
+ public void testRangingCallbacks() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+
+ // Invoke vendor service callbacks and ensure that the corresponding app callback is
+ // invoked.
+ mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
+ verify(cb).onRangingOpened(sessionHandle);
+
+ mRangingCbCaptor.getValue().onRangingOpenFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingOpenFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters);
+ verify(cb).onRangingStarted(sessionHandle, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStartFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingStartFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingReconfigured(sessionHandle, parameters);
+ verify(cb).onRangingReconfigured(sessionHandle, parameters);
+
+ mRangingCbCaptor.getValue().onRangingReconfigureFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingReconfigureFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStopped(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingStopped(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ mRangingCbCaptor.getValue().onRangingStopFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingStopFailed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+
+ final RangingReport rangingReport = new RangingReport.Builder().build();
+ mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport);
+ verify(cb).onRangingResult(sessionHandle, rangingReport);
+
+ mRangingCbCaptor.getValue().onRangingClosed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ verify(cb).onRangingClosed(
+ sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters);
+ }
+
+ @Test
+ public void testHandleClientDeath() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+
+ verify(cbBinder).linkToDeath(mClientDeathCaptor.capture(), anyInt());
+ assertThat(mClientDeathCaptor.getValue()).isNotNull();
+
+ clearInvocations(cb);
+
+ // Invoke cb, ensure it reaches the client.
+ mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
+ verify(cb).onRangingOpened(sessionHandle);
+
+ // Trigger client death and ensure the session is stopped.
+ mClientDeathCaptor.getValue().binderDied();
+ verify(mVendorService).stopRanging(sessionHandle);
+ verify(mVendorService).closeRanging(sessionHandle);
+
+ // Invoke cb, it should be ignored.
+ mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters);
+ verify(cb, never()).onRangingStarted(any(), any());
+ }
+
+ @Test
+ public void testHandleVendorServiceDeath() throws Exception {
+ final SessionHandle sessionHandle = new SessionHandle(5);
+ final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class);
+ final PersistableBundle parameters = new PersistableBundle();
+ final IBinder cbBinder = mock(IBinder.class);
+ when(cb.asBinder()).thenReturn(cbBinder);
+
+ mUwbServiceImpl.openRanging(sessionHandle, cb, parameters);
+
+ verify(mVendorServiceBinder).linkToDeath(mVendorServiceDeathCaptor.capture(), anyInt());
+ assertThat(mVendorServiceDeathCaptor.getValue()).isNotNull();
+
+ verify(mVendorService).openRanging(
+ eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters));
+ assertThat(mRangingCbCaptor.getValue()).isNotNull();
+
+ clearInvocations(cb);
+
+ // Invoke cb, ensure it reaches the client.
+ mRangingCbCaptor.getValue().onRangingOpened(sessionHandle);
+ verify(cb).onRangingOpened(sessionHandle);
+
+ // Trigger vendor service death and ensure that the client is informed of session end.
+ mVendorServiceDeathCaptor.getValue().binderDied();
+ verify(cb).onRangingClosed(
+ eq(sessionHandle), eq(RangingSession.Callback.REASON_UNKNOWN),
+ argThat((p) -> p.isEmpty()));
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index 809b6d5..182848b4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -123,6 +123,7 @@
for (long i = cal.getTimeInMillis(); i >= 5; i--) {
File file = mock(File.class);
when(file.getName()).thenReturn(String.valueOf(i));
+ when(file.getAbsolutePath()).thenReturn(String.valueOf(i));
AtomicFile af = new AtomicFile(file);
expectedFiles.add(af);
mDataBase.mHistoryFiles.addLast(af);
@@ -133,6 +134,7 @@
for (int i = 5; i >= 0; i--) {
File file = mock(File.class);
when(file.getName()).thenReturn(String.valueOf(cal.getTimeInMillis() - i));
+ when(file.getAbsolutePath()).thenReturn(String.valueOf(cal.getTimeInMillis() - i));
AtomicFile af = new AtomicFile(file);
mDataBase.mHistoryFiles.addLast(af);
}
@@ -158,6 +160,7 @@
for (long i = cal.getTimeInMillis(); i >= 5; i--) {
File file = mock(File.class);
when(file.getName()).thenReturn(i + ".bak");
+ when(file.getAbsolutePath()).thenReturn(i + ".bak");
AtomicFile af = new AtomicFile(file);
mDataBase.mHistoryFiles.addLast(af);
}
@@ -415,4 +418,36 @@
assertThat(mDataBase.mBuffer).isNotEqualTo(nh);
verify(mAlarmManager, times(1)).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
}
+
+ @Test
+ public void testRemoveFilePathFromHistory_hasMatch() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ AtomicFile af = mock(AtomicFile.class);
+ when(af.getBaseFile()).thenReturn(new File(mRootDir, "af" + i));
+ mDataBase.mHistoryFiles.addLast(af);
+ }
+ // Baseline size of history files
+ assertThat(mDataBase.mHistoryFiles.size()).isEqualTo(5);
+
+ // Remove only file number 3
+ String filePathToRemove = new File(mRootDir, "af3").getAbsolutePath();
+ mDataBase.removeFilePathFromHistory(filePathToRemove);
+ assertThat(mDataBase.mHistoryFiles.size()).isEqualTo(4);
+ }
+
+ @Test
+ public void testRemoveFilePathFromHistory_noMatch() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ AtomicFile af = mock(AtomicFile.class);
+ when(af.getBaseFile()).thenReturn(new File(mRootDir, "af" + i));
+ mDataBase.mHistoryFiles.addLast(af);
+ }
+ // Baseline size of history files
+ assertThat(mDataBase.mHistoryFiles.size()).isEqualTo(5);
+
+ // Attempt to remove a filename that doesn't exist, expect nothing to break or change
+ String filePathToRemove = new File(mRootDir, "af.thisfileisfake").getAbsolutePath();
+ mDataBase.removeFilePathFromHistory(filePathToRemove);
+ assertThat(mDataBase.mHistoryFiles.size()).isEqualTo(5);
+ }
}
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 87efaa2..37d7198 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5057,7 +5057,8 @@
}
@Test
- public void testToastRateLimiterCanPreventShowCallForCustomToast() throws Exception {
+ public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()
+ throws Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
@@ -5075,30 +5076,7 @@
INotificationManager nmService = (INotificationManager) mService.mService;
nmService.enqueueToast(testPackage, token, callback, 2000, 0);
- verify(callback, times(0)).show(any());
- }
-
- @Test
- public void testCustomToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception {
- final String testPackage = "testPackageName";
- assertEquals(0, mService.mToastQueue.size());
- mService.isSystemUid = false;
- setToastRateIsWithinQuota(false); // rate limit reached
- // Avoids rate limiting.
- setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true);
-
- // package is not suspended
- when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
- .thenReturn(false);
-
- setAppInForegroundForToasts(mUid, true);
-
- Binder token = new Binder();
- ITransientNotification callback = mock(ITransientNotification.class);
- INotificationManager nmService = (INotificationManager) mService.mService;
-
- nmService.enqueueToast(testPackage, token, callback, 2000, 0);
- verify(callback).show(any());
+ verify(callback, times(1)).show(any());
}
@Test
@@ -5206,12 +5184,14 @@
}
@Test
- public void testToastRateLimiterCanPreventShowCallForTextToast() throws Exception {
+ public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()
+ throws Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
setToastRateIsWithinQuota(false); // rate limit reached
setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
+ setAppInForegroundForToasts(mUid, false);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5226,12 +5206,35 @@
}
@Test
+ public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()
+ throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+ setToastRateIsWithinQuota(false); // rate limit reached
+ setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
+ setAppInForegroundForToasts(mUid, true);
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ Binder token = new Binder();
+ INotificationManager nmService = (INotificationManager) mService.mService;
+
+ nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
+ verify(mStatusBar, times(1))
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ }
+
+ @Test
public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
setToastRateIsWithinQuota(false); // rate limit reached
setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true);
+ setAppInForegroundForToasts(mUid, false);
// package is not suspended
when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 678defe..57cf865 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -23,17 +23,27 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doCallRealMethod;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
import androidx.test.filters.FlakyTest;
@@ -426,4 +436,104 @@
AppTransitionController.getAnimationTargets(
opening, closing, false /* visible */));
}
-}
+
+ static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
+ @Override
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ }
+
+ @Override
+ public void onAnimationCancelled() throws RemoteException {
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return new Binder();
+ }
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideEmpty() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ assertNull(mAppTransitionController.getRemoteAnimationOverride(activity,
+ TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideWindowContainer() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
+ activity.registerRemoteAnimations(definition);
+
+ assertEquals(adapter,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ assertNull(mAppTransitionController.getRemoteAnimationOverride(
+ null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideTransitionController() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
+ mAppTransitionController.registerRemoteAnimations(definition);
+
+ assertEquals(adapter,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ assertEquals(adapter,
+ mAppTransitionController.getRemoteAnimationOverride(
+ null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideBoth() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1);
+ activity.registerRemoteAnimations(definition1);
+
+ final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition2.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, adapter2);
+ mAppTransitionController.registerRemoteAnimations(definition2);
+
+ assertEquals(adapter2,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>()));
+ assertEquals(adapter2,
+ mAppTransitionController.getRemoteAnimationOverride(
+ null, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>()));
+ }
+
+ @Test
+ public void testGetRemoteAnimationOverrideWindowContainerHasPriority() {
+ final ActivityRecord activity = createActivityRecord(mDisplayContent);
+ final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1);
+ activity.registerRemoteAnimations(definition1);
+
+ final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition2.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter2);
+ mAppTransitionController.registerRemoteAnimations(definition2);
+
+ assertEquals(adapter1,
+ mAppTransitionController.getRemoteAnimationOverride(
+ activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
+ }
+}
\ No newline at end of file
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 7c2cfab..ee1d393 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1515,6 +1515,129 @@
assertEquals(primarySplitBounds, letterboxedBounds);
}
+ @Test
+ public void testUpdateResolvedBoundsHorizontalPosition_left() {
+ // Display configured as (2800, 1400).
+ assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxHorizontalPositionMultiplier */ 0.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(0, 0, 700, 1400),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(0, 0, 700, 1400),
+ // After the display is resized to (700, 1400).
+ /* sizeCompatScaled */ new Rect(0, 0, 350, 700));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsHorizontalPosition_center() {
+ // Display configured as (2800, 1400).
+ assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxHorizontalPositionMultiplier */ 0.5f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400),
+ // After the display is resized to (700, 1400).
+ /* sizeCompatScaled */ new Rect(525, 0, 875, 700));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsHorizontalPosition_invalidMultiplier_defaultToCenter() {
+ // Display configured as (2800, 1400).
+
+ // Below 0.0.
+ assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxHorizontalPositionMultiplier */ -1.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400),
+ // After the display is resized to (700, 1400).
+ /* sizeCompatScaled */ new Rect(525, 0, 875, 700));
+
+ // Above 1.0
+ assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxHorizontalPositionMultiplier */ 2.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400),
+ // After the display is resized to (700, 1400).
+ /* sizeCompatScaled */ new Rect(525, 0, 875, 700));
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsHorizontalPosition_right() {
+ // Display configured as (2800, 1400).
+ assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity(
+ /* letterboxHorizontalPositionMultiplier */ 1.0f,
+ // At launch.
+ /* fixedOrientationLetterbox */ new Rect(2100, 0, 2800, 1400),
+ // After 90 degree rotation.
+ /* sizeCompatUnscaled */ new Rect(700, 0, 1400, 1400),
+ // After the display is resized to (700, 1400).
+ /* sizeCompatScaled */ new Rect(1050, 0, 1400, 700));
+ }
+
+ private void assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity(
+ float letterboxHorizontalPositionMultiplier, Rect fixedOrientationLetterbox,
+ Rect sizeCompatUnscaled, Rect sizeCompatScaled) {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.setLetterboxHorizontalPositionMultiplier(
+ letterboxHorizontalPositionMultiplier);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ assertEquals(fixedOrientationLetterbox, mActivity.getBounds());
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ assertTrue(mActivity.inSizeCompatMode());
+ // Activity is in size compat mode but not scaled.
+ assertEquals(sizeCompatUnscaled, mActivity.getBounds());
+
+ // Force activity to scaled down for size compat mode.
+ resizeDisplay(mTask.mDisplayContent, 700, 1400);
+
+ assertTrue(mActivity.inSizeCompatMode());
+ assertScaled();
+ assertEquals(sizeCompatScaled, mActivity.getBounds());
+ }
+
+ @Test
+ public void testUpdateResolvedBoundsHorizontalPosition_activityFillParentWidth() {
+ // When activity width equals parent width, multiplier shouldn't have any effect.
+ assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxHorizontalPositionMultiplier */ 0.0f);
+ assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxHorizontalPositionMultiplier */ 0.5f);
+ assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ /* letterboxHorizontalPositionMultiplier */ 1.0f);
+ }
+
+ private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
+ float letterboxHorizontalPositionMultiplier) {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ mActivity.mWmService.setLetterboxHorizontalPositionMultiplier(
+ letterboxHorizontalPositionMultiplier);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+ assertFitted();
+
+ // Rotate to put activity in size compat mode.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ assertTrue(mActivity.inSizeCompatMode());
+ // Activity is in size compat mode but not scaled.
+ assertEquals(new Rect(0, 0, 1400, 700), mActivity.getBounds());
+ }
+
private static WindowState addWindowToActivity(ActivityRecord activity) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index afaf1b1..491fe98 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -110,6 +110,7 @@
private ActivityTaskManagerService mAtmService;
private WindowManagerService mWmService;
private TestWindowManagerPolicy mWMPolicy;
+ private TestDisplayWindowSettingsProvider mTestDisplayWindowSettingsProvider;
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
@@ -284,10 +285,12 @@
mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
mWMPolicy = new TestWindowManagerPolicy(this::getWindowManagerService,
mPowerManagerWrapper);
+ mTestDisplayWindowSettingsProvider = new TestDisplayWindowSettingsProvider();
// Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
mWmService = WindowManagerService.main(
- mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new,
+ mContext, mImService, false, false, mWMPolicy, mAtmService,
+ mTestDisplayWindowSettingsProvider, StubTransaction::new,
() -> mSurfaceFactory.get(), (unused) -> new MockSurfaceControlBuilder());
spyOn(mWmService);
spyOn(mWmService.mRoot);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index 777149b..ce2d748 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -147,10 +147,6 @@
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
final TestDisplayContent newDisplay = createInternal(display);
- // Ensure letterbox aspect ratio is not overridden on any device target.
- // {@link com.android.internal.R.dimen.config_taskLetterboxAspectRatio}, provided by
- // the below method, is set on some device form factors.
- mService.mWindowManager.setFixedOrientationLetterboxAspectRatio(0);
// disable the normal system decorations
final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy();
spyOn(displayPolicy);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
new file mode 100644
index 0000000..b2e44b1
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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.wm;
+
+import android.annotation.NonNull;
+import android.view.DisplayInfo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * In-memory DisplayWindowSettingsProvider used in tests. Ensures no settings are read from or
+ * written to device-specific display settings files.
+ */
+public final class TestDisplayWindowSettingsProvider extends DisplayWindowSettingsProvider {
+
+ private final Map<String, SettingsEntry> mOverrideSettingsMap = new HashMap<>();
+
+ @Override
+ @NonNull
+ public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+ // Because no settings are read from settings files, there is no need to store base
+ // settings. Only override settings are necessary to track because they can be modified
+ // during tests (e.g. display size, ignore orientation requests).
+ return getOverrideSettings(info);
+ }
+
+ @Override
+ @NonNull
+ public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+ return new SettingsEntry(getOrCreateOverrideSettingsEntry(info));
+ }
+
+ @Override
+ public void updateOverrideSettings(@NonNull DisplayInfo info,
+ @NonNull SettingsEntry overrides) {
+ final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+ overrideSettings.setTo(overrides);
+ }
+
+ @NonNull
+ private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info);
+ SettingsEntry settings;
+ if ((settings = mOverrideSettingsMap.get(identifier)) != null) {
+ return settings;
+ }
+ settings = new SettingsEntry();
+ mOverrideSettingsMap.put(identifier, settings);
+ return settings;
+ }
+
+ /**
+ * In {@link TestDisplayWindowSettingsProvider}, always use uniqueId as the identifier.
+ */
+ private static String getIdentifier(DisplayInfo displayInfo) {
+ return displayInfo.uniqueId;
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index ae8e2de..acadb74 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -210,7 +210,7 @@
}
@Override
- public boolean okToAnimate() {
+ public boolean okToAnimate(boolean ignoreScreenOn) {
return mOkToAnimate;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index dd0c9e6..d9aa871 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -23,6 +23,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -50,7 +51,13 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.view.IWindowSessionCallback;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.View;
+import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -250,4 +257,31 @@
eq(clientToken), eq(windowToken), anyInt(), eq(TYPE_INPUT_METHOD),
eq(windowToken.mOptions));
}
+
+ @Test
+ public void testAddWindowWithSubWindowTypeByWindowContext() {
+ spyOn(mWm.mWindowContextListenerController);
+
+ final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay);
+ final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float v) throws RemoteException {}
+ });
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ TYPE_APPLICATION_ATTACHED_DIALOG);
+ params.token = windowToken.token;
+ final IBinder windowContextToken = new Binder();
+ params.setWindowContextToken(windowContextToken);
+ doReturn(true).when(mWm.mWindowContextListenerController)
+ .hasListener(eq(windowContextToken));
+ doReturn(TYPE_INPUT_METHOD).when(mWm.mWindowContextListenerController)
+ .getWindowType(eq(windowContextToken));
+
+ mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY,
+ UserHandle.USER_SYSTEM, new InsetsState(), null, new InsetsState(),
+ new InsetsSourceControl[0]);
+
+ verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(),
+ any(), anyInt(), anyInt(), any());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 39fdb2d..ae12062 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -55,6 +55,8 @@
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
@@ -99,6 +101,7 @@
import com.android.internal.policy.AttributeCache;
import com.android.internal.util.ArrayUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.Description;
@@ -153,6 +156,22 @@
*/
Transaction mTransaction;
+ /**
+ * Whether device-specific global overrides have already been checked in
+ * {@link WindowTestsBase#setUpBase()}.
+ */
+ private static boolean sGlobalOverridesChecked;
+ /**
+ * Whether device-specific overrides have already been checked in
+ * {@link WindowTestsBase#setUpBase()} when the default display is used.
+ */
+ private static boolean sOverridesCheckedDefaultDisplay;
+ /**
+ * Whether device-specific overrides have already been checked in
+ * {@link WindowTestsBase#setUpBase()} when a {@link TestDisplayContent} is used.
+ */
+ private static boolean sOverridesCheckedTestDisplay;
+
@BeforeClass
public static void setUpOnceBase() {
AttributeCache.init(getInstrumentation().getTargetContext());
@@ -190,6 +209,43 @@
// {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set
// on some device form factors.
mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio(0);
+ // Ensure letterbox position multiplier is not overridden on any device target.
+ // {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
+ // may be set on some device form factors.
+ mAtm.mWindowManager.setLetterboxHorizontalPositionMultiplier(0.5f);
+
+ checkDeviceSpecificOverridesNotApplied();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Revert back to device overrides.
+ mAtm.mWindowManager.setFixedOrientationLetterboxAspectRatio(
+ mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio));
+ mAtm.mWindowManager.setLetterboxHorizontalPositionMultiplier(
+ mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier));
+ }
+
+ /**
+ * Check that device-specific overrides are not applied. Only need to check once during entire
+ * test run for each case: global overrides, default display, and test display.
+ */
+ private void checkDeviceSpecificOverridesNotApplied() {
+ // Check global overrides
+ if (!sGlobalOverridesChecked) {
+ assertEquals(0, mWm.getFixedOrientationLetterboxAspectRatio(), 0 /* delta */);
+ sGlobalOverridesChecked = true;
+ }
+ // Check display-specific overrides
+ if (!sOverridesCheckedDefaultDisplay && mDisplayContent == mDefaultDisplay) {
+ assertFalse(mDisplayContent.getIgnoreOrientationRequest());
+ sOverridesCheckedDefaultDisplay = true;
+ } else if (!sOverridesCheckedTestDisplay && mDisplayContent instanceof TestDisplayContent) {
+ assertFalse(mDisplayContent.getIgnoreOrientationRequest());
+ sOverridesCheckedTestDisplay = true;
+ }
}
private void createTestDisplay(UseTestDisplay annotation) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a6b68e1..309673d 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -24,6 +24,7 @@
import static android.app.usage.UsageEvents.Event.LOCUS_ID_SET;
import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION;
import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION;
+import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
import static android.app.usage.UsageEvents.Event.USER_STOPPED;
import static android.app.usage.UsageEvents.Event.USER_UNLOCKED;
import static android.app.usage.UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
@@ -112,6 +113,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
@@ -1988,6 +1990,17 @@
}
@Override
+ public void reportUserInteraction(String packageName, int userId) {
+ Objects.requireNonNull(packageName);
+ if (!isCallingUidSystem()) {
+ throw new SecurityException("Only system is allowed to call reportUserInteraction");
+ }
+ final Event event = new Event(USER_INTERACTION, SystemClock.elapsedRealtime());
+ event.mPackage = packageName;
+ reportEventOrAddToQueue(userId, event);
+ }
+
+ @Override
public void registerAppUsageObserver(int observerId,
String[] packages, long timeLimitMs, PendingIntent
callbackIntent, String callingPackage) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 2e692e6..7f24c36 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -2139,6 +2139,12 @@
Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+ "forceRestart=" + forceRestart);
}
+ if (mCurrentGadgetHalVersion < UsbManager.GADGET_HAL_V1_2) {
+ if ((functions & UsbManager.FUNCTION_NCM) != 0) {
+ Slog.e(TAG, "Could not set unsupported function for the GadgetHal");
+ return;
+ }
+ }
if (mCurrentFunctions != functions
|| !mCurrentFunctionsApplied
|| forceRestart) {
diff --git a/services/uwb/Android.bp b/services/uwb/Android.bp
new file mode 100644
index 0000000..da30d43
--- /dev/null
+++ b/services/uwb/Android.bp
@@ -0,0 +1,26 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "services.uwb-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+ name: "services.uwb",
+ defaults: ["platform_service_defaults"],
+ srcs: [
+ ":services.uwb-sources",
+ ],
+ libs: [
+ "services.core",
+ ],
+}
diff --git a/services/uwb/java/com/android/server/uwb/UwbInjector.java b/services/uwb/java/com/android/server/uwb/UwbInjector.java
new file mode 100644
index 0000000..00c0aca
--- /dev/null
+++ b/services/uwb/java/com/android/server/uwb/UwbInjector.java
@@ -0,0 +1,48 @@
+/*
+ * 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.uwb;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.uwb.IUwbAdapter;
+
+
+/**
+ * To be used for dependency injection (especially helps mocking static dependencies).
+ */
+public class UwbInjector {
+ private static final String TAG = "UwbInjector";
+
+ private static final String VENDOR_SERVICE_NAME = "uwb_vendor";
+
+ private final Context mContext;
+
+ public UwbInjector(@NonNull Context context) {
+ mContext = context;
+ }
+
+ /**
+ * @return Returns the vendor service handle.
+ */
+ public IUwbAdapter getVendorService() {
+ IBinder b = ServiceManager.getService(VENDOR_SERVICE_NAME);
+ if (b == null) return null;
+ return IUwbAdapter.Stub.asInterface(b);
+ }
+}
diff --git a/services/uwb/java/com/android/server/uwb/UwbService.java b/services/uwb/java/com/android/server/uwb/UwbService.java
new file mode 100644
index 0000000..4bb280f
--- /dev/null
+++ b/services/uwb/java/com/android/server/uwb/UwbService.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.uwb;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+/**
+ * Uwb System service.
+ */
+public class UwbService extends SystemService {
+ private static final String TAG = "UwbService";
+
+ private final UwbServiceImpl mImpl;
+
+ public UwbService(Context context) {
+ super(context);
+ mImpl = new UwbServiceImpl(context, new UwbInjector(context));
+ }
+
+ @Override
+ public void onStart() {
+ Log.i(TAG, "Registering " + Context.UWB_SERVICE);
+ publishBinderService(Context.UWB_SERVICE, mImpl);
+ }
+}
diff --git a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
new file mode 100644
index 0000000..70bd20e
--- /dev/null
+++ b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java
@@ -0,0 +1,288 @@
+/*
+ * 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.uwb;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.uwb.IUwbAdapter;
+import android.uwb.IUwbAdapterStateCallbacks;
+import android.uwb.IUwbRangingCallbacks;
+import android.uwb.RangingReport;
+import android.uwb.RangingSession;
+import android.uwb.SessionHandle;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Map;
+
+/**
+ * Implementation of {@link android.uwb.IUwbAdapter} binder service.
+ */
+public class UwbServiceImpl extends IUwbAdapter.Stub implements IBinder.DeathRecipient{
+ private static final String TAG = "UwbServiceImpl";
+
+ private final Context mContext;
+ private final UwbInjector mUwbInjector;
+ /**
+ * Map for storing the callbacks wrapper for each session.
+ */
+ @GuardedBy("mCallbacksMap")
+ private final Map<SessionHandle, UwbRangingCallbacksWrapper> mCallbacksMap = new ArrayMap<>();
+
+ /**
+ * Used for caching the vendor implementation of {@link IUwbAdapter} interface.
+ */
+ private IUwbAdapter mVendorUwbAdapter;
+
+ /**
+ * Wrapper for callback registered with vendor service. This wrapper is needed for performing
+ * permission check before sending the callback to the external app.
+ *
+ * Access to these callbacks are synchronized.
+ */
+ private class UwbRangingCallbacksWrapper extends IUwbRangingCallbacks.Stub
+ implements IBinder.DeathRecipient{
+ private final SessionHandle mSessionHandle;
+ private final IUwbRangingCallbacks mExternalCb;
+ private boolean mIsValid;
+
+ UwbRangingCallbacksWrapper(@NonNull SessionHandle sessionHandle,
+ @NonNull IUwbRangingCallbacks externalCb) {
+ mSessionHandle = sessionHandle;
+ mExternalCb = externalCb;
+ mIsValid = true;
+
+ // Link to death for external callback.
+ linkToDeath();
+ }
+
+ private void linkToDeath() {
+ IBinder binder = mExternalCb.asBinder();
+ try {
+ binder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to link to client death event.", e);
+ }
+ }
+
+ private void removeClientAndUnlinkToDeath() {
+ // Remove from the map.
+ synchronized (mCallbacksMap) {
+ mCallbacksMap.remove(mSessionHandle);
+ }
+ IBinder binder = mExternalCb.asBinder();
+ binder.unlinkToDeath(this, 0);
+ mIsValid = false;
+ }
+
+
+ @Override
+ public synchronized void onRangingOpened(SessionHandle sessionHandle)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingOpened(sessionHandle);
+ }
+
+ @Override
+ public synchronized void onRangingOpenFailed(SessionHandle sessionHandle,
+ int reason, PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingOpenFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStarted(SessionHandle sessionHandle,
+ PersistableBundle parameters)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStarted(sessionHandle, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStartFailed(SessionHandle sessionHandle,
+ int reason, PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStartFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingReconfigured(SessionHandle sessionHandle,
+ PersistableBundle parameters)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingReconfigured(sessionHandle, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingReconfigureFailed(SessionHandle sessionHandle,
+ int reason, PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingReconfigureFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStopped(SessionHandle sessionHandle, int reason,
+ PersistableBundle parameters)
+ throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStopped(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingStopFailed(SessionHandle sessionHandle, int reason,
+ PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingStopFailed(sessionHandle, reason, parameters);
+ }
+
+ @Override
+ public synchronized void onRangingClosed(SessionHandle sessionHandle, int reason,
+ PersistableBundle parameters) throws RemoteException {
+ if (!mIsValid) return;
+ mExternalCb.onRangingClosed(sessionHandle, reason, parameters);
+ removeClientAndUnlinkToDeath();
+ }
+
+ @Override
+ public synchronized void onRangingResult(SessionHandle sessionHandle,
+ RangingReport rangingReport)
+ throws RemoteException {
+ if (!mIsValid) return;
+ // TODO: Perform permission checks and noteOp.
+ mExternalCb.onRangingResult(sessionHandle, rangingReport);
+ }
+
+ @Override
+ public synchronized void binderDied() {
+ if (!mIsValid) return;
+ Log.i(TAG, "Client died: ending session: " + mSessionHandle);
+ try {
+ removeClientAndUnlinkToDeath();
+ stopRanging(mSessionHandle);
+ closeRanging(mSessionHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote exception while handling client death", e);
+ }
+ }
+ }
+
+ private void linkToVendorServiceDeath() {
+ IBinder binder = mVendorUwbAdapter.asBinder();
+ try {
+ binder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to link to vendor service death event.", e);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ Log.i(TAG, "Vendor service died: sending session close callbacks");
+ synchronized (mCallbacksMap) {
+ for (Map.Entry<SessionHandle, UwbRangingCallbacksWrapper> e : mCallbacksMap.entrySet()) {
+ try {
+ e.getValue().mExternalCb.onRangingClosed(
+ e.getKey(), RangingSession.Callback.REASON_UNKNOWN,
+ new PersistableBundle());
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to send session close callback " + e.getKey(), ex);
+ }
+ }
+ // Clear all sessions.
+ mCallbacksMap.clear();
+ }
+ mVendorUwbAdapter = null;
+ }
+
+ private synchronized IUwbAdapter getVendorUwbAdapter() throws IllegalStateException {
+ if (mVendorUwbAdapter != null) return mVendorUwbAdapter;
+ mVendorUwbAdapter = mUwbInjector.getVendorService();
+ if (mVendorUwbAdapter == null) {
+ throw new IllegalStateException("No vendor service found!");
+ }
+ Log.i(TAG, "Retrieved vendor service");
+ linkToVendorServiceDeath();
+ return mVendorUwbAdapter;
+ }
+
+ UwbServiceImpl(@NonNull Context context, @NonNull UwbInjector uwbInjector) {
+ mContext = context;
+ mUwbInjector = uwbInjector;
+ }
+
+ @Override
+ public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
+ throws RemoteException {
+ getVendorUwbAdapter().registerAdapterStateCallbacks(adapterStateCallbacks);
+ }
+
+ @Override
+ public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
+ throws RemoteException {
+ getVendorUwbAdapter().unregisterAdapterStateCallbacks(adapterStateCallbacks);
+ }
+
+ @Override
+ public long getTimestampResolutionNanos() throws RemoteException {
+ return getVendorUwbAdapter().getTimestampResolutionNanos();
+ }
+
+ @Override
+ public PersistableBundle getSpecificationInfo() throws RemoteException {
+ return getVendorUwbAdapter().getSpecificationInfo();
+ }
+
+ @Override
+ public void openRanging(SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks,
+ PersistableBundle parameters) throws RemoteException {
+ UwbRangingCallbacksWrapper wrapperCb =
+ new UwbRangingCallbacksWrapper(sessionHandle, rangingCallbacks);
+ synchronized (mCallbacksMap) {
+ mCallbacksMap.put(sessionHandle, wrapperCb);
+ }
+ getVendorUwbAdapter().openRanging(sessionHandle, wrapperCb, parameters);
+ }
+
+ @Override
+ public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters)
+ throws RemoteException {
+ // TODO: Perform permission checks.
+ getVendorUwbAdapter().startRanging(sessionHandle, parameters);
+ }
+
+ @Override
+ public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters)
+ throws RemoteException {
+ getVendorUwbAdapter().reconfigureRanging(sessionHandle, parameters);
+ }
+
+ @Override
+ public void stopRanging(SessionHandle sessionHandle) throws RemoteException {
+ getVendorUwbAdapter().stopRanging(sessionHandle);
+ }
+
+ @Override
+ public void closeRanging(SessionHandle sessionHandle) throws RemoteException {
+ getVendorUwbAdapter().closeRanging(sessionHandle);
+ }
+
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index bcfb302..6f701f7 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -434,7 +434,8 @@
}
try {
AudioRecord audioRecord = new AudioRecord(
- new AudioAttributes.Builder().setHotwordModeEnabled(true).build(),
+ new AudioAttributes.Builder()
+ .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(),
audioFormat,
getBufferSizeInBytes(
audioFormat.getSampleRate(),
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index f6d18fc..96e715e 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -637,18 +637,18 @@
this.band = band;
this.downlinkLowKhz = downlinkLowKhz;
this.downlinkOffset = downlinkOffset;
+ this.downlinkRange = downlinkRange;
this.uplinkLowKhz = uplinkLowKhz;
this.uplinkOffset = uplinkOffset;
- this.downlinkRange = downlinkRange;
this.uplinkRange = uplinkRange;
}
int band;
int downlinkLowKhz;
int downlinkOffset;
+ int downlinkRange;
int uplinkLowKhz;
int uplinkOffset;
- int downlinkRange;
int uplinkRange;
}
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index f29f3bd..6b82045 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -598,7 +598,8 @@
: earfcnFrequency.downlinkOffset;
break;
} else {
- Log.e(TAG, "Band and the range of EARFCN are not consistent.");
+ Rlog.w(TAG,"Band and the range of EARFCN are not consistent: band = " + band
+ + " ,earfcn = " + earfcn + " ,isUplink = " + isUplink);
return INVALID_FREQUENCY;
}
}
@@ -617,7 +618,7 @@
}
private static boolean isInEarfcnRange(int earfcn, EutranBandArfcnFrequency earfcnFrequency,
- boolean isUplink) {
+ boolean isUplink) {
if (isUplink) {
return earfcn >= earfcnFrequency.uplinkOffset && earfcn <= earfcnFrequency.uplinkRange;
} else {
@@ -640,7 +641,8 @@
: uarfcnFrequency.downlinkOffset;
break;
} else {
- Log.e(TAG, "Band and the range of UARFCN are not consistent.");
+ Rlog.w(TAG,"Band and the range of UARFCN are not consistent: band = " + band
+ + " ,uarfcn = " + uarfcn + " ,isUplink = " + isUplink);
return INVALID_FREQUENCY;
}
}
@@ -716,7 +718,8 @@
arfcnOffset);
break;
} else {
- Log.e(TAG, "Band and the range of ARFCN are not consistent.");
+ Rlog.w(TAG,"Band and the range of ARFCN are not consistent: band = " + band
+ + " ,arfcn = " + arfcn + " ,isUplink = " + isUplink);
return INVALID_FREQUENCY;
}
}
@@ -733,7 +736,7 @@
* Downlink actual frequency(kHz) = Uplink actual frequency + 10
*/
private static int convertArfcnToFrequency(int arfcn, int uplinkFrequencyFirstKhz,
- int arfcnOffset) {
+ int arfcnOffset) {
return uplinkFrequencyFirstKhz + 200 * (arfcn - arfcnOffset);
}
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index c8ed82c..0539897 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1055,6 +1055,20 @@
*/
public static final int HANDOVER_FAILED = 0x10006;
+ /**
+ * Enterprise setup failure: duplicate CID in DataCallResponse.
+ *
+ * @hide
+ */
+ public static final int DUPLICATE_CID = 0x10007;
+
+ /**
+ * Enterprise setup failure: no default data connection set up yet.
+ *
+ * @hide
+ */
+ public static final int NO_DEFAULT_DATA = 0x10008;
+
private static final Map<Integer, String> sFailCauseMap;
static {
sFailCauseMap = new HashMap<>();
@@ -1481,6 +1495,9 @@
sFailCauseMap.put(UNACCEPTABLE_NETWORK_PARAMETER,
"UNACCEPTABLE_NETWORK_PARAMETER");
sFailCauseMap.put(LOST_CONNECTION, "LOST_CONNECTION");
+ sFailCauseMap.put(HANDOVER_FAILED, "HANDOVER_FAILED");
+ sFailCauseMap.put(DUPLICATE_CID, "DUPLICATE_CID");
+ sFailCauseMap.put(NO_DEFAULT_DATA, "NO_DEFAULT_DATA");
}
private DataFailCause() {
@@ -1580,6 +1597,7 @@
add(RADIO_NOT_AVAILABLE);
add(UNACCEPTABLE_NETWORK_PARAMETER);
add(SIGNAL_LOST);
+ add(DUPLICATE_CID);
}
};
}
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index d21fcab..391372a 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -203,23 +203,6 @@
}
/**
- * @return the UTF-8 encoded SIP message.
- * @deprecated Use {@link #toEncodedMessage} instead
- */
- @Deprecated
- public @NonNull byte[] getEncodedMessage() {
- byte[] header = new StringBuilder()
- .append(mStartLine)
- .append(mHeaderSection)
- .append(CRLF)
- .toString().getBytes(UTF_8);
- byte[] sipMessage = new byte[header.length + mContent.length];
- System.arraycopy(header, 0, sipMessage, 0, header.length);
- System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
- return sipMessage;
- }
-
- /**
* According RFC-3261 section 7, SIP is a text protocol and uses the UTF-8 charset. Its format
* consists of a start-line, one or more header fields, an empty line indicating the end of the
* header fields, and an optional message-body.
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
index ec85995..2d230a7 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
@@ -23,6 +23,7 @@
import android.app.blob.LeaseInfo;
import android.content.Context;
import android.content.res.Resources;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -56,6 +57,16 @@
}
}
+ public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input)
+ throws IOException {
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
+ try (FileOutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
+ session.openWrite(0, -1))) {
+ FileUtils.copy(in, out);
+ }
+ }
+ }
+
public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input,
long lengthBytes) throws IOException {
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index ed0a98d..0593615 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -19,19 +19,21 @@
import android.platform.helpers.IAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_WINDOW_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
-const val WALLPAPER_TITLE = "Wallpaper"
+val LAUNCHER_TITLE = arrayOf("Wallpaper", "Launcher", "com.google.android.googlequicksearchbox")
fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
assertWm {
- this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
+ this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME)
}
}
fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
assertWm {
- this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
+ this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME)
}
}
@@ -39,23 +41,23 @@
assertWm {
this.showsAppWindowOnTop(testApp.getPackage())
.then()
- .showsAppWindowOnTop("Launcher")
+ .showsAppWindowOnTop(*LAUNCHER_TITLE)
}
}
-fun FlickerTestParameter.wallpaperWindowBecomesVisible() {
+fun FlickerTestParameter.launcherWindowBecomesVisible() {
assertWm {
- this.hidesBelowAppWindow(WALLPAPER_TITLE)
+ this.hidesBelowAppWindow(*LAUNCHER_TITLE)
.then()
- .showsBelowAppWindow(WALLPAPER_TITLE)
+ .showsBelowAppWindow(*LAUNCHER_TITLE)
}
}
-fun FlickerTestParameter.wallpaperWindowBecomesInvisible() {
+fun FlickerTestParameter.launcherWindowBecomesInvisible() {
assertWm {
- this.showsBelowAppWindow(WALLPAPER_TITLE)
+ this.showsBelowAppWindow(*LAUNCHER_TITLE)
.then()
- .hidesBelowAppWindow(WALLPAPER_TITLE)
+ .hidesBelowAppWindow(*LAUNCHER_TITLE)
}
}
@@ -130,15 +132,15 @@
fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
if (rotatesScreen) {
assertLayers {
- this.isVisible(STATUS_BAR_WINDOW_NAME)
+ this.isVisible(STATUS_BAR_LAYER_NAME)
.then()
- .isInvisible(STATUS_BAR_WINDOW_NAME)
+ .isInvisible(STATUS_BAR_LAYER_NAME)
.then()
- .isVisible(STATUS_BAR_WINDOW_NAME)
+ .isVisible(STATUS_BAR_LAYER_NAME)
}
} else {
assertLayers {
- this.isVisible(STATUS_BAR_WINDOW_NAME)
+ this.isVisible(STATUS_BAR_LAYER_NAME)
}
}
}
@@ -168,34 +170,27 @@
val endingPos = WindowUtils.getStatusBarPosition(endRotation)
assertLayersStart {
- this.visibleRegion(STATUS_BAR_WINDOW_NAME).coversExactly(startingPos)
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(startingPos)
}
assertLayersEnd {
- this.visibleRegion(STATUS_BAR_WINDOW_NAME).coversExactly(endingPos)
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(endingPos)
}
}
-fun FlickerTestParameter.appLayerReplacesWallpaperLayer(appName: String) {
+fun FlickerTestParameter.appLayerReplacesLauncher(appName: String) {
assertLayers {
- this.isVisible(WALLPAPER_TITLE)
+ this.isVisible(*LAUNCHER_TITLE)
.then()
- .isInvisible(WALLPAPER_TITLE)
.isVisible(appName)
}
}
-fun FlickerTestParameter.wallpaperLayerReplacesAppLayer(testApp: IAppHelper) {
+fun FlickerTestParameter.launcherLayerReplacesApp(testApp: IAppHelper) {
assertLayers {
this.isVisible(testApp.getPackage())
.then()
.isInvisible(testApp.getPackage())
- .isVisible(WALLPAPER_TITLE)
- }
-}
-
-fun FlickerTestParameter.layerAlwaysVisible(packageName: String) {
- assertLayers {
- this.isVisible(packageName)
+ .isVisible(*LAUNCHER_TITLE)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index c92d40c..db91eb2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,12 +16,14 @@
package com.android.server.wm.flicker.close
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -44,6 +46,30 @@
}
}
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun launcherLayerReplacesApp() {
+ super.launcherLayerReplacesApp()
+ }
+
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun launcherReplacesAppWindowAsTopWindow() {
+ super.launcherReplacesAppWindowAsTopWindow()
+ }
+
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun launcherWindowBecomesVisible() {
+ super.launcherWindowBecomesVisible()
+ }
+
+ @FlakyTest(bugId = 185401242)
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index a524466..9ac504b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -36,8 +36,8 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
-import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
+import com.android.server.wm.flicker.launcherLayerReplacesApp
+import com.android.server.wm.flicker.launcherWindowBecomesVisible
import org.junit.Test
abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
@@ -76,16 +76,16 @@
testSpec.statusBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible()
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible()
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
@FlakyTest
@@ -130,13 +130,13 @@
@Presubmit
@Test
- open fun wallpaperWindowBecomesVisible() {
- testSpec.wallpaperWindowBecomesVisible()
+ open fun launcherWindowBecomesVisible() {
+ testSpec.launcherWindowBecomesVisible()
}
@Presubmit
@Test
- open fun wallpaperLayerReplacesAppLayer() {
- testSpec.wallpaperLayerReplacesAppLayer(testApp)
+ open fun launcherLayerReplacesApp() {
+ testSpec.launcherLayerReplacesApp(testApp)
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 90c2338..3bd19ea 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -18,6 +18,7 @@
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -50,6 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 185400889)
class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
@@ -64,7 +66,7 @@
}
}
teardown {
- test {
+ eachRun {
testApp.exit(wmHelper)
}
}
@@ -104,7 +106,7 @@
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
@@ -141,7 +143,10 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 5,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index dfb229d..3cb58b9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -19,6 +19,7 @@
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -65,7 +66,7 @@
}
}
teardown {
- test {
+ eachRun {
testApp.exit(wmHelper)
}
}
@@ -95,24 +96,24 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
- @Presubmit
+ @FlakyTest
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
Surface.ROTATION_0)
- @Presubmit
+ @FlakyTest
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
@@ -132,7 +133,7 @@
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
@@ -150,7 +151,10 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 1,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 6b8bf63..cdec51d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -76,11 +76,11 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
@@ -106,7 +106,7 @@
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Presubmit
+ @FlakyTest
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
@@ -138,7 +138,7 @@
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
}
- @Presubmit
+ @FlakyTest
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 9b37caf..22d3418 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -20,6 +20,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -97,11 +98,11 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
- @Presubmit
+ @FlakyTest
@Test
fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 7ba9db1..bb9cd6f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -34,7 +34,6 @@
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
@@ -113,7 +112,11 @@
@Presubmit
@Test
- fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`)
+ fun layerAlwaysVisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.`package`)
+ }
+ }
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index be0357e..55bbe3a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -33,8 +33,8 @@
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesLauncher
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
@@ -107,7 +107,7 @@
@Presubmit
@Test
- fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
+ fun launcherWindowBecomesInvisible() = testSpec.launcherWindowBecomesInvisible()
@Presubmit
@Test
@@ -138,8 +138,8 @@
@Presubmit
@Test
- fun appLayerReplacesWallpaperLayer() =
- testSpec.appLayerReplacesWallpaperLayer(testAppComponentName.className)
+ fun appLayerReplacesLauncher() =
+ testSpec.appLayerReplacesLauncher(testAppComponentName.className)
@FlakyTest
@Test
@@ -168,9 +168,9 @@
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
repetitions = 1,
+ supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
- WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY
)
)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 8e73ab1..d0e9556 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -19,6 +19,7 @@
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -51,6 +52,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest
class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = SimpleAppHelper(instrumentation)
@@ -131,7 +133,7 @@
.getConfigNonRotationTests(
repetitions = 3,
supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
)
)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index 130860d..6a7309c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -18,10 +18,11 @@
import android.platform.helpers.IAppHelper
import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.LAUNCHER_TITLE
fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) {
assertWm {
- this.showsAppWindowOnTop("Launcher")
+ this.showsAppWindowOnTop(*LAUNCHER_TITLE)
.then()
.showsAppWindowOnTop("Snapshot", testApp.getPackage())
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 024983d..559d953 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -66,6 +66,18 @@
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun focusChanges() {
+ super.focusChanges()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 62b9b81..ad7ee30 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -25,7 +25,7 @@
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
import org.junit.Test
@@ -70,8 +70,8 @@
@Postsubmit
@Test
- override fun wallpaperWindowBecomesInvisible() {
- testSpec.wallpaperWindowBecomesInvisible()
+ override fun launcherWindowBecomesInvisible() {
+ testSpec.launcherWindowBecomesInvisible()
}
@FlakyTest
@@ -98,6 +98,12 @@
super.focusChanges()
}
+ @FlakyTest(bugId = 185400889)
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index cd5c61a..26e77b6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -19,10 +19,11 @@
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.appLayerReplacesLauncher
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusChanges
@@ -39,7 +40,7 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
import org.junit.Test
abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@@ -75,13 +76,13 @@
testSpec.navBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible()
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
@@ -93,10 +94,10 @@
testSpec.statusBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible()
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
}
@Presubmit
@@ -134,13 +135,13 @@
testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
}
- @Presubmit
+ @FlakyTest
@Test
- open fun appLayerReplacesWallpaperLayer() {
- testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
+ open fun appLayerReplacesLauncher() {
+ testSpec.appLayerReplacesLauncher(testApp.`package`)
}
- @Presubmit
+ @FlakyTest
@Test
open fun appWindowReplacesLauncherAsTopWindow() {
testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
@@ -148,7 +149,7 @@
@Presubmit
@Test
- open fun wallpaperWindowBecomesInvisible() {
- testSpec.wallpaperWindowBecomesInvisible()
+ open fun launcherWindowBecomesInvisible() {
+ testSpec.launcherWindowBecomesInvisible()
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 38af8a7d..741aad7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -71,10 +72,28 @@
@FlakyTest
@Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
+ @Presubmit
+ @Test
+ override fun launcherWindowBecomesInvisible() {
+ super.launcherWindowBecomesInvisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 35ad597..5a8162e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -58,7 +57,13 @@
super.focusDoesNotChange()
}
- @Presubmit
+ @FlakyTest
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
+ @FlakyTest
@Test
fun screenshotLayerBecomesInvisible() {
testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 2989035..ab8ebd9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -36,6 +36,7 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.Test
abstract class RotationTransition(protected val testSpec: FlickerTestParameter) {
@@ -68,16 +69,16 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarWindowIsAlwaysVisible() {
testSpec.navBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible()
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = true)
}
@FlakyTest
@@ -87,16 +88,16 @@
testSpec.config.startRotation, testSpec.config.endRotation)
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarWindowIsAlwaysVisible() {
testSpec.statusBarWindowIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest
@Test
open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible()
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = true)
}
@FlakyTest
@@ -110,7 +111,12 @@
@Test
open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers = listOf(WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
+ "SecondaryHomeHandle"
+ )
+ )
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index fe444bd..a353c59 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -24,7 +23,6 @@
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
-import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.Test
@@ -60,27 +58,37 @@
@FlakyTest(bugId = 140855415)
@Test
- override fun navBarLayerRotatesAndScales() {
- super.navBarLayerRotatesAndScales()
+ override fun statusBarWindowIsAlwaysVisible() {
+ super.statusBarWindowIsAlwaysVisible()
}
@FlakyTest(bugId = 140855415)
@Test
- override fun statusBarLayerRotatesScales() {
- super.statusBarLayerRotatesScales()
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
}
- @Presubmit
+ @FlakyTest(bugId = 185400889)
+ @Test
+ override fun noUncoveredRegions() {
+ super.noUncoveredRegions()
+ }
+
+ @FlakyTest(bugId = 185400889)
@Test
fun appLayerAlwaysVisible() {
- testSpec.layerAlwaysVisible(testApp.`package`)
+ testSpec.assertLayers {
+ isVisible(testApp.`package`)
+ }
}
- @Presubmit
+ @FlakyTest(bugId = 185400889)
@Test
fun appLayerRotates() {
testSpec.assertLayers {
this.coversExactly(startingPos, testApp.`package`)
+ .then()
+ .coversExactly(endingPos, testApp.`package`)
}
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 0bb0337..642b19e 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -527,6 +527,33 @@
}
@Test
+ public void testExpireSession_Phase1_Install() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ Install.single(TestApp.A2).setEnableRollback().setStaged().commit();
+ }
+
+ @Test
+ public void testExpireSession_Phase2_VerifyInstall() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(rollback.isStaged()).isTrue();
+ }
+
+ @Test
+ public void testExpireSession_Phase3_VerifyRollback() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ }
+
+ @Test
public void hasMainlineModule() throws Exception {
String pkgName = getModuleMetadataPackageName();
boolean existed = InstrumentationRegistry.getInstrumentation().getContext()
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 304567a3..1aa5c24 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -40,7 +40,9 @@
import org.junit.runner.RunWith;
import java.io.File;
+import java.time.Instant;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -582,6 +584,27 @@
runPhase("testWatchdogMonitorsAcrossReboots_Phase3_VerifyRollback");
}
+ /**
+ * Tests an available rollback shouldn't be deleted when its session expires.
+ */
+ @Test
+ public void testExpireSession() throws Exception {
+ runPhase("testExpireSession_Phase1_Install");
+ getDevice().reboot();
+ runPhase("testExpireSession_Phase2_VerifyInstall");
+
+ // Advance system clock by 7 days to expire the staged session
+ Instant t1 = Instant.ofEpochMilli(getDevice().getDeviceDate());
+ Instant t2 = t1.plusMillis(TimeUnit.DAYS.toMillis(7));
+ runAsRoot(() -> getDevice().setDate(Date.from(t2)));
+
+ // Somehow we need to wait for a while before reboot. Otherwise the change to the
+ // system clock will be reset after reboot.
+ Thread.sleep(3000);
+ getDevice().reboot();
+ runPhase("testExpireSession_Phase3_VerifyRollback");
+ }
+
private void pushTestApex() throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
index d573e93..4f11669 100644
--- a/tests/UpdatableSystemFontTest/AndroidTest.xml
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -19,6 +19,11 @@
<!-- This test requires root to side load fs-verity cert. -->
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="EmojiRenderingTestApp.apk" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
new file mode 100644
index 0000000..ed34fa9
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "EmojiRenderingTestApp",
+ manifest: "AndroidManifest.xml",
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..5d8f5fc
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.emojirenderingtestapp">
+ <application>
+ <activity android:name=".EmojiRenderingTestActivity"/>
+ </application>
+</manifest>
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
new file mode 100644
index 0000000..947e9c2
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * 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.emojirenderingtestapp;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/** Test app to render an emoji. */
+public class EmojiRenderingTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout container = new LinearLayout(this);
+ container.setOrientation(LinearLayout.VERTICAL);
+ TextView textView = new TextView(this);
+ textView.setText("\uD83E\uDD72"); // 🥲
+ container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(container);
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index e684556..032da3f 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -36,7 +36,6 @@
import org.junit.runner.RunWith;
import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -47,6 +46,9 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
+ private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
+ private static final String DATA_FONTS_DIR = "/data/fonts/files/";
+
private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der";
private static final Pattern PATTERN_FONT = Pattern.compile("path = ([^, \n]*)");
@@ -72,6 +74,14 @@
private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG =
"/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig";
+ private static final String EMOJI_RENDERING_TEST_APP_ID = "com.android.emojirenderingtestapp";
+ private static final String EMOJI_RENDERING_TEST_ACTIVITY =
+ EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity";
+
+ private interface ThrowingSupplier<T> {
+ T get() throws Exception;
+ }
+
@Rule
public final AddFsVerityCertRule mAddFsverityCertRule =
new AddFsVerityCertRule(this, CERT_PATH);
@@ -91,7 +101,10 @@
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data/fonts/files/");
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+ // The updated font should be readable and unmodifiable.
+ expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
+ expectRemoteCommandToFail("echo -n '' >> " + fontPath);
}
@Test
@@ -102,8 +115,12 @@
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath2).startsWith("/data/fonts/files/");
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
assertThat(fontPath2).isNotEqualTo(fontPath);
+ // The new file should be readable.
+ expectRemoteCommandToSucceed("cat " + fontPath2 + " > /dev/null");
+ // The old file should be still readable.
+ expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
}
@Test
@@ -119,25 +136,14 @@
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data/fonts/files/");
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
assertThat(fontPath2).isNotEqualTo(fontPath);
- assertThat(fontPath2).startsWith("/data/fonts/files/");
- assertThat(fontPath3).startsWith("/data/fonts/files/");
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath3).startsWith(DATA_FONTS_DIR);
assertThat(fontPath3).isNotEqualTo(fontPath);
}
@Test
- public void updatedFont_dataFileIsImmutableAndReadable() throws Exception {
- expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
- TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
- String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data");
-
- expectRemoteCommandToFail("echo -n '' >> " + fontPath);
- expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
- }
-
- @Test
public void updateFont_invalidCert() throws Exception {
expectRemoteCommandToFail(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
@@ -158,11 +164,37 @@
}
@Test
+ public void launchApp() throws Exception {
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
+ assertThat(fontPath).startsWith(SYSTEM_FONTS_DIR);
+ expectRemoteCommandToSucceed("am force-stop " + EMOJI_RENDERING_TEST_APP_ID);
+ expectRemoteCommandToSucceed("am start-activity -n " + EMOJI_RENDERING_TEST_ACTIVITY);
+ waitUntil(TimeUnit.SECONDS.toMillis(5), () ->
+ isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID));
+ }
+
+ @Test
+ public void launchApp_afterUpdateFont() throws Exception {
+ String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
+ assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
+ expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
+ assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
+ expectRemoteCommandToSucceed("am force-stop " + EMOJI_RENDERING_TEST_APP_ID);
+ expectRemoteCommandToSucceed("am start-activity -n " + EMOJI_RENDERING_TEST_ACTIVITY);
+ // The original font should NOT be opened by the app.
+ waitUntil(TimeUnit.SECONDS.toMillis(5), () ->
+ isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID)
+ && !isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID));
+ }
+
+ @Test
public void reboot() throws Exception {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
- assertThat(fontPath).startsWith("/data/fonts/files/");
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
expectRemoteCommandToSucceed("stop");
expectRemoteCommandToSucceed("start");
@@ -210,16 +242,40 @@
});
}
- private void waitUntil(long timeoutMillis, Supplier<Boolean> func) {
+ private void waitUntil(long timeoutMillis, ThrowingSupplier<Boolean> func) {
long untilMillis = System.currentTimeMillis() + timeoutMillis;
do {
- if (func.get()) return;
try {
+ if (func.get()) return;
Thread.sleep(100);
} catch (InterruptedException e) {
throw new AssertionError("Interrupted", e);
+ } catch (Exception e) {
+ throw new AssertionError("Unexpected exception", e);
}
} while (System.currentTimeMillis() < untilMillis);
throw new AssertionError("Timed out");
}
+
+ private boolean isFileOpenedBy(String path, String appId) throws DeviceNotAvailableException {
+ String pid = pidOf(appId);
+ if (pid.isEmpty()) {
+ return false;
+ }
+ CommandResult result = getDevice().executeShellV2Command(
+ String.format("lsof -t -p %s '%s'", pid, path));
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ return false;
+ }
+ // The file is open if the output of lsof is non-empty.
+ return !result.getStdout().trim().isEmpty();
+ }
+
+ private String pidOf(String appId) throws DeviceNotAvailableException {
+ CommandResult result = getDevice().executeShellV2Command("pidof " + appId);
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ return "";
+ }
+ return result.getStdout().trim();
+ }
}
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index 454d5b5..2b45b3d 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -44,6 +44,9 @@
setSubscriberId("MySubId")
setPartialConnectivityAcceptable(false)
setUnvalidatedConnectivityAcceptable(true)
+ if (isAtLeastS()) {
+ setBypassableVpn(true)
+ }
}.build()
if (isAtLeastS()) {
// From S, the config will have 12 items
@@ -66,6 +69,7 @@
if (isAtLeastS()) {
setNat64DetectionEnabled(false)
setProvisioningNotificationEnabled(false)
+ setBypassableVpn(true)
}
}.build()
@@ -78,6 +82,7 @@
if (isAtLeastS()) {
assertFalse(config.isNat64DetectionEnabled())
assertFalse(config.isProvisioningNotificationEnabled())
+ assertTrue(config.isBypassableVpn())
} else {
assertTrue(config.isNat64DetectionEnabled())
assertTrue(config.isProvisioningNotificationEnabled())
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
index 56f9df7..39c424e 100644
--- a/tests/net/integration/Android.bp
+++ b/tests/net/integration/Android.bp
@@ -25,6 +25,7 @@
android_test {
name: "FrameworksNetIntegrationTests",
+ defaults: ["framework-connectivity-test-defaults"],
platform_apis: true,
certificate: "platform",
srcs: [
@@ -61,6 +62,7 @@
// Utilities for testing framework code both in integration and unit tests.
java_library {
name: "frameworks-net-integration-testutils",
+ defaults: ["framework-connectivity-test-defaults"],
srcs: ["util/**/*.java", "util/**/*.kt"],
static_libs: [
"androidx.annotation_annotation",
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 6cbdd25..19f8843 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -384,7 +384,7 @@
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
- manager.requestBackgroundNetwork(request, handler, callback);
+ manager.requestBackgroundNetwork(request, callback, handler);
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 47e4b5e..039ce2f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4313,7 +4313,7 @@
final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build(),
- mCsHandlerThread.getThreadHandler(), cellBgCallback);
+ cellBgCallback, mCsHandlerThread.getThreadHandler());
// Make callbacks for monitoring.
final NetworkRequest request = new NetworkRequest.Builder().build();
@@ -9768,7 +9768,8 @@
return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
nc, new NetworkScore.Builder().setLegacyInt(0).build(),
mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
- INVALID_UID, mQosCallbackTracker, new ConnectivityService.Dependencies());
+ INVALID_UID, TEST_LINGER_DELAY_MS, mQosCallbackTracker,
+ new ConnectivityService.Dependencies());
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 116d755e..36e229d 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -71,6 +71,8 @@
static final int LOW_DAILY_LIMIT = 2;
static final int HIGH_DAILY_LIMIT = 1000;
+ private static final int TEST_LINGER_DELAY_MS = 400;
+
LingerMonitor mMonitor;
@Mock ConnectivityService mConnService;
@@ -366,7 +368,7 @@
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
- mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
+ mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), TEST_LINGER_DELAY_MS,
mQosCallbackTracker, new ConnectivityService.Dependencies());
nai.everValidated = true;
return nai;
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index b592000..0c7363e 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -153,21 +153,19 @@
verify(mConnectivityManager)
.requestBackgroundNetwork(
eq(getWifiRequest(expectedSubIds)),
- any(),
- any(NetworkBringupCallback.class));
+ any(NetworkBringupCallback.class),
+ any());
for (final int subId : expectedSubIds) {
verify(mConnectivityManager)
.requestBackgroundNetwork(
eq(getCellRequestForSubId(subId)),
- any(),
- any(NetworkBringupCallback.class));
+ any(NetworkBringupCallback.class), any());
}
verify(mConnectivityManager)
.requestBackgroundNetwork(
eq(getRouteSelectionRequest(expectedSubIds)),
- any(),
- any(RouteSelectionCallback.class));
+ any(RouteSelectionCallback.class), any());
}
@Test
@@ -267,8 +265,8 @@
verify(mConnectivityManager)
.requestBackgroundNetwork(
eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
- any(),
- mRouteSelectionCallbackCaptor.capture());
+ mRouteSelectionCallbackCaptor.capture(),
+ any());
RouteSelectionCallback cb = mRouteSelectionCallbackCaptor.getValue();
cb.onAvailable(mNetwork);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index a2223e8..95a9726 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -89,7 +89,7 @@
mNetworkAgent = mock(VcnNetworkAgent.class);
doReturn(mNetworkAgent)
.when(mDeps)
- .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
+ .newNetworkAgent(any(), any(), any(), any(), any(), any(), any(), any(), any());
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
@@ -216,7 +216,7 @@
any(),
any(),
any(),
- anyInt(),
+ any(),
any(),
any(),
any(),
@@ -244,7 +244,7 @@
any(String.class),
ncCaptor.capture(),
lpCaptor.capture(),
- anyInt(),
+ any(),
argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
any(),
any(),
@@ -297,7 +297,7 @@
startingInternalAddrs.equals(lp.getLinkAddresses())
&& Collections.singletonList(TEST_DNS_ADDR)
.equals(lp.getDnsServers())),
- anyInt(),
+ any(),
any(),
any(),
any(),
@@ -356,7 +356,7 @@
any(),
any(),
any(),
- anyInt(),
+ any(),
any(),
any(),
unwantedCallbackCaptor.capture(),
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 5f27fab..ac0edaa 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -65,6 +65,7 @@
TEST_SUBSCRIPTION_SNAPSHOT,
mConfig,
mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
mDeps);
vgc.setIsQuitting(true);
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index ced8745..9705f0f 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
@@ -89,7 +91,8 @@
doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong());
}
- private void verifyBuildNetworkCapabilitiesCommon(int transportType) {
+ private void verifyBuildNetworkCapabilitiesCommon(
+ int transportType, boolean isMobileDataEnabled) {
final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder();
capBuilder.addTransportType(transportType);
capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
@@ -109,10 +112,22 @@
capBuilder.build(), new LinkProperties(), false);
final NetworkCapabilities vcnCaps =
VcnGatewayConnection.buildNetworkCapabilities(
- VcnGatewayConnectionConfigTest.buildTestConfig(), record);
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ record,
+ isMobileDataEnabled);
+
assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+ if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) {
+ assertEquals(isMobileDataEnabled, vcnCaps.hasCapability(cap));
+ } else {
+ assertTrue(vcnCaps.hasCapability(cap));
+ }
+ }
+
assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
@@ -126,12 +141,17 @@
@Test
public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception {
- verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI);
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI, true /* isMobileDataEnabled */);
}
@Test
public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception {
- verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR);
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, true /* isMobileDataEnabled */);
+ }
+
+ @Test
+ public void testBuildNetworkCapabilitiesMobileDataDisabled() throws Exception {
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 98d553d..284f1f8 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -202,6 +202,7 @@
TEST_SUBSCRIPTION_SNAPSHOT,
mConfig,
mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
mDeps);
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
index f943f34..72db55b 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
@@ -16,12 +16,18 @@
package com.android.server.vcn;
+import static android.net.NetworkProvider.NetworkOfferCallback;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.os.test.TestLooper;
@@ -33,18 +39,23 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.List;
/** Tests for TelephonySubscriptionTracker */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnNetworkProviderTest {
private static final int TEST_SCORE_UNSATISFIED = 0;
- private static final int TEST_SCORE_HIGH = 100;
private static final int TEST_PROVIDER_ID = 1;
@NonNull private final Context mContext;
@NonNull private final TestLooper mTestLooper;
+ @NonNull private VcnNetworkProvider.Dependencies mDeps;
+ @NonNull private ConnectivityManager mConnMgr;
@NonNull private VcnNetworkProvider mVcnNetworkProvider;
@NonNull private NetworkRequestListener mListener;
@@ -55,27 +66,48 @@
@Before
public void setUp() throws Exception {
- mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper());
+ mDeps = mock(VcnNetworkProvider.Dependencies.class);
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper(), mDeps);
mListener = mock(NetworkRequestListener.class);
}
+ private NetworkOfferCallback verifyRegisterAndGetOfferCallback() throws Exception {
+ mVcnNetworkProvider.register();
+
+ final ArgumentCaptor<NetworkOfferCallback> cbCaptor =
+ ArgumentCaptor.forClass(NetworkOfferCallback.class);
+
+ verify(mConnMgr).registerNetworkProvider(eq(mVcnNetworkProvider));
+ verify(mDeps)
+ .registerNetworkOffer(
+ eq(mVcnNetworkProvider),
+ argThat(
+ score ->
+ score.getLegacyInt()
+ == Vcn.getNetworkScore().getLegacyInt()),
+ any(),
+ any(),
+ cbCaptor.capture());
+
+ return cbCaptor.getValue();
+ }
+
+ @Test
+ public void testRegister() throws Exception {
+ verifyRegisterAndGetOfferCallback();
+ }
+
@Test
public void testRequestsPassedToRegisteredListeners() throws Exception {
mVcnNetworkProvider.registerListener(mListener);
final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
- verify(mListener).onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
- }
-
- @Test
- public void testRequestsPassedToRegisteredListeners_satisfiedByHighScoringProvider()
- throws Exception {
- mVcnNetworkProvider.registerListener(mListener);
-
- final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID);
- verify(mListener).onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
+ verify(mListener).onNetworkRequested(request);
}
@Test
@@ -84,7 +116,33 @@
mVcnNetworkProvider.unregisterListener(mListener);
final NetworkRequest request = mock(NetworkRequest.class);
- mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
+ verifyNoMoreInteractions(mListener);
+ }
+
+ @Test
+ public void testCachedRequestsPassedOnRegister() throws Exception {
+ final List<NetworkRequest> requests = new ArrayList<>();
+ final NetworkOfferCallback offerCb = verifyRegisterAndGetOfferCallback();
+
+ for (int i = 0; i < 10; i++) {
+ // Build unique network requests; in this case, iterate down the capabilities as a way
+ // to unique-ify requests.
+ final NetworkRequest request =
+ new NetworkRequest.Builder().clearCapabilities().addCapability(i).build();
+
+ requests.add(request);
+ offerCb.onNetworkNeeded(request);
+ }
+
+ // Remove one, and verify that it is never sent to the listeners.
+ final NetworkRequest removed = requests.remove(0);
+ offerCb.onNetworkUnneeded(removed);
+
+ mVcnNetworkProvider.registerListener(mListener);
+ for (NetworkRequest request : requests) {
+ verify(mListener).onNetworkRequested(request);
+ }
verifyNoMoreInteractions(mListener);
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 90eb75e..736fabd 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -16,16 +16,24 @@
package com.android.server.vcn;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static com.android.server.vcn.Vcn.VcnContentResolver;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -35,12 +43,16 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.database.ContentObserver;
import android.net.NetworkRequest;
+import android.net.Uri;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.os.ParcelUuid;
import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
import android.util.ArraySet;
import com.android.server.VcnManagementService.VcnCallback;
@@ -53,23 +65,31 @@
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
public class VcnTest {
private static final String PKG_NAME = VcnTest.class.getPackage().getName();
private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
- private static final int NETWORK_SCORE = 0;
- private static final int PROVIDER_ID = 5;
+ private static final boolean MOBILE_DATA_ENABLED = true;
+ private static final Set<Integer> TEST_SUB_IDS_IN_GROUP =
+ new ArraySet<>(Arrays.asList(1, 2, 3));
private static final int[][] TEST_CAPS =
new int[][] {
- new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET},
- new int[] {NET_CAPABILITY_DUN}
+ new int[] {NET_CAPABILITY_IMS, NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN},
+ new int[] {NET_CAPABILITY_CBS, NET_CAPABILITY_INTERNET},
+ new int[] {NET_CAPABILITY_FOTA, NET_CAPABILITY_DUN},
+ new int[] {NET_CAPABILITY_MMS}
};
private Context mContext;
private VcnContext mVcnContext;
+ private TelephonyManager mTelephonyManager;
+ private VcnContentResolver mContentResolver;
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
private VcnNetworkProvider mVcnNetworkProvider;
private VcnCallback mVcnCallback;
@@ -86,6 +106,9 @@
public void setUp() {
mContext = mock(Context.class);
mVcnContext = mock(VcnContext.class);
+ mTelephonyManager =
+ setupAndGetTelephonyManager(MOBILE_DATA_ENABLED /* isMobileDataEnabled */);
+ mContentResolver = mock(VcnContentResolver.class);
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
mVcnCallback = mock(VcnCallback.class);
@@ -97,12 +120,15 @@
doReturn(mContext).when(mVcnContext).getContext();
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+ doReturn(mContentResolver).when(mDeps).newVcnContentResolver(eq(mVcnContext));
// Setup VcnGatewayConnection instance generation
doAnswer((invocation) -> {
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
return mock(VcnGatewayConnection.class);
- }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any());
+ }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any(), anyBoolean());
+
+ doReturn(TEST_SUB_IDS_IN_GROUP).when(mSubscriptionSnapshot).getAllSubIdsInGroup(any());
mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
@@ -123,6 +149,16 @@
mDeps);
}
+ private TelephonyManager setupAndGetTelephonyManager(boolean isMobileDataEnabled) {
+ final TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, telephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
+ doReturn(isMobileDataEnabled).when(telephonyManager).isDataEnabled();
+
+ return telephonyManager;
+ }
+
private NetworkRequestListener verifyAndGetRequestListener() {
ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
ArgumentCaptor.forClass(NetworkRequestListener.class);
@@ -139,7 +175,7 @@
requestBuilder.addCapability(netCapability);
}
- requestListener.onNetworkRequested(requestBuilder.build(), NETWORK_SCORE, PROVIDER_ID);
+ requestListener.onNetworkRequested(requestBuilder.build());
mTestLooper.dispatchAll();
}
@@ -164,6 +200,39 @@
}
@Test
+ public void testContentObserverRegistered() {
+ // Validate state from setUp()
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
+ verify(mContentResolver)
+ .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class));
+ }
+
+ @Test
+ public void testMobileDataStateCheckedOnInitialization_enabled() {
+ // Validate state from setUp()
+ assertTrue(mVcn.isMobileDataEnabled());
+ verify(mTelephonyManager).isDataEnabled();
+ }
+
+ @Test
+ public void testMobileDataStateCheckedOnInitialization_disabled() {
+ // Build and setup new telephonyManager to ensure method call count is reset.
+ final TelephonyManager telephonyManager =
+ setupAndGetTelephonyManager(false /* isMobileDataEnabled */);
+ final Vcn vcn =
+ new Vcn(
+ mVcnContext,
+ TEST_SUB_GROUP,
+ mConfig,
+ mSubscriptionSnapshot,
+ mVcnCallback,
+ mDeps);
+
+ assertFalse(vcn.isMobileDataEnabled());
+ verify(mTelephonyManager).isDataEnabled();
+ }
+
+ @Test
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
}
@@ -193,7 +262,8 @@
eq(TEST_SUB_GROUP),
eq(mSubscriptionSnapshot),
any(),
- mGatewayStatusCallbackCaptor.capture());
+ mGatewayStatusCallbackCaptor.capture(),
+ eq(MOBILE_DATA_ENABLED));
return gatewayConnections;
}
@@ -256,20 +326,21 @@
mTestLooper.dispatchAll();
// Verify that the VCN requests the networkRequests be resent
- assertEquals(1, mVcn.getVcnGatewayConnections().size());
+ assertEquals(gatewayConnections.size() - 1, mVcn.getVcnGatewayConnections().size());
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
// Verify that the VcnGatewayConnection is restarted if a request exists for it
triggerVcnRequestListeners(requestListener);
mTestLooper.dispatchAll();
- assertEquals(2, mVcn.getVcnGatewayConnections().size());
+ assertEquals(gatewayConnections.size(), mVcn.getVcnGatewayConnections().size());
verify(mDeps, times(gatewayConnections.size() + 1))
.newVcnGatewayConnection(
eq(mVcnContext),
eq(TEST_SUB_GROUP),
eq(mSubscriptionSnapshot),
any(),
- mGatewayStatusCallbackCaptor.capture());
+ mGatewayStatusCallbackCaptor.capture(),
+ anyBoolean());
}
@Test
@@ -286,7 +357,7 @@
public void testUpdateConfigReevaluatesGatewayConnections() {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
startGatewaysAndGetGatewayConnections(requestListener);
- assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
+ assertEquals(TEST_CAPS.length, mVcn.getVcnGatewayConnectionConfigMap().size());
// Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
// down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
@@ -309,4 +380,57 @@
verify(removedGatewayConnection).teardownAsynchronously();
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
}
+
+ private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) {
+ final ArgumentCaptor<ContentObserver> captor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture());
+ final ContentObserver contentObserver = captor.getValue();
+
+ // Start VcnGatewayConnections
+ mVcn.setMobileDataEnabled(startingToggleState);
+ triggerVcnRequestListeners(verifyAndGetRequestListener());
+ final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> gateways =
+ mVcn.getVcnGatewayConnectionConfigMap();
+
+ // Trigger data toggle change.
+ doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled();
+ contentObserver.onChange(false /* selfChange, ignored */);
+ mTestLooper.dispatchAll();
+
+ // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the
+ // toggle state changed.
+ for (Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry : gateways.entrySet()) {
+ final Set<Integer> exposedCaps = entry.getKey().getAllExposedCapabilities();
+ if (startingToggleState != endingToggleState
+ && (exposedCaps.contains(NET_CAPABILITY_INTERNET)
+ || exposedCaps.contains(NET_CAPABILITY_DUN))) {
+ verify(entry.getValue()).teardownAsynchronously();
+ } else {
+ verify(entry.getValue(), never()).teardownAsynchronously();
+ }
+ }
+
+ assertEquals(endingToggleState, mVcn.isMobileDataEnabled());
+ }
+
+ @Test
+ public void testMobileDataEnabled() {
+ verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataDisabled() {
+ verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataObserverFiredWithoutChanges_dataEnabled() {
+ verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataObserverFiredWithoutChanges_dataDisabled() {
+ verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */);
+ }
}
diff --git a/tools/hiddenapi/checksorted_sha.sh b/tools/hiddenapi/checksorted_sha.sh
index 451fed6..72fb867 100755
--- a/tools/hiddenapi/checksorted_sha.sh
+++ b/tools/hiddenapi/checksorted_sha.sh
@@ -1,10 +1,10 @@
#!/bin/bash
set -e
LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
-git show --name-only --pretty=format: $1 | grep "boot/hiddenapi/hiddenapi-.*txt" | while read file; do
+git show --name-only --pretty=format: $1 | grep "hiddenapi/hiddenapi-.*txt" | while read file; do
diff <(git show $1:$file) <(git show $1:$file | $LOCAL_DIR/sort_api.sh ) || {
echo -e "\e[1m\e[31m$file $1 is not sorted or contains duplicates. To sort it correctly:\e[0m"
- echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $2/frameworks/base/$file\e[0m"
+ echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $PWD/$file\e[0m"
exit 1
}
done
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 822aba4..8b18f9b 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -10,7 +10,6 @@
android.system \
android.test \
com.android.bouncycastle \
- com.android.i18n.phonenumbers \
com.android.okhttp \
com.sun \
dalvik \