Merge "Controls - Remove controls from lockscreen, use wallet" into sc-dev
diff --git a/Android.bp b/Android.bp
index e4c5c37..df8b15f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -344,8 +344,8 @@
genrule {
name: "statslog-telephony-common-java-gen",
tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common"
- + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
+ cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" +
+ " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"],
}
@@ -371,7 +371,6 @@
srcs: [
// Java/AIDL sources under frameworks/base
":framework-blobstore-sources",
- ":framework-connectivity-sources", // framework-connectivity is not yet a module
":framework-core-sources",
":framework-drm-sources",
":framework-graphics-nonupdatable-sources",
@@ -422,6 +421,7 @@
":resourcemanager_aidl",
":storaged_aidl",
":vold_aidl",
+ ":deviceproductinfoconstants_aidl",
// For the generated R.java and Manifest.java
":framework-res{.aapt.srcjar}",
@@ -437,6 +437,7 @@
name: "framework-updatable-sources",
srcs: [
":framework-appsearch-sources",
+ ":framework-connectivity-sources",
":framework-graphics-srcs",
":framework-mediaprovider-sources",
":framework-permission-sources",
@@ -639,6 +640,7 @@
defaults: ["framework-aidl-export-defaults"],
srcs: [
":framework-non-updatable-sources",
+ ":framework-connectivity-sources",
"core/java/**/*.logtags",
],
// See comment on framework-atb-backward-compatibility module below
@@ -700,6 +702,8 @@
apex_available: ["//apex_available:platform"],
visibility: [
"//frameworks/base",
+ // TODO: remove when framework-connectivity can build against API
+ "//frameworks/base/packages/Connectivity/framework",
// TODO(b/147128803) remove the below lines
"//frameworks/base/apex/appsearch/framework",
"//frameworks/base/apex/blobstore/framework",
@@ -746,8 +750,8 @@
}
platform_compat_config {
- name: "framework-platform-compat-config",
- src: ":framework-minus-apex",
+ name: "framework-platform-compat-config",
+ src: ":framework-minus-apex",
}
// A temporary build target that is conditionally included on the bootclasspath if
@@ -768,7 +772,7 @@
name: "statslog-framework-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
- " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
+ " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
@@ -877,7 +881,7 @@
java_library {
name: "framework-annotations-lib",
- srcs: [ ":framework-annotations" ],
+ srcs: [":framework-annotations"],
sdk_version: "core_current",
}
@@ -1155,7 +1159,6 @@
},
}
-
// This is the full proto version of libplatformprotos. It may only
// be used by test code that is not shipped on the device.
cc_library {
@@ -1221,68 +1224,58 @@
path: "core/java",
}
-aidl_interface {
- name: "libincremental_aidl",
- unstable: true,
+cc_defaults {
+ name: "incremental_default",
+ host_supported: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wextra-semi",
+ "-Werror",
+ "-Wzero-as-null-pointer-constant",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ aidl: {
+ include_dirs: [
+ "frameworks/native/aidl/binder",
+ ],
+ export_aidl_headers: true,
+ },
+}
+
+cc_library {
+ name: "libincremental_aidl-cpp",
srcs: [
":incremental_aidl",
],
- backend: {
- java: {
- sdk_version: "28",
- },
- cpp: {
- enabled: true,
- },
- ndk: {
- enabled: true,
- },
- },
+ defaults: ["incremental_default"],
}
-aidl_interface {
- name: "libdataloader_aidl",
- unstable: true,
+cc_library {
+ name: "libdataloader_aidl-cpp",
srcs: [
":dataloader_aidl",
],
- imports: [
- "libincremental_aidl",
+ defaults: ["incremental_default"],
+ shared_libs: [
+ "libincremental_aidl-cpp",
],
- backend: {
- java: {
- sdk_version: "28",
- },
- cpp: {
- enabled: true,
- },
- ndk: {
- enabled: false,
- },
- },
}
-aidl_interface {
- name: "libincremental_manager_aidl",
- unstable: true,
+cc_library {
+ name: "libincremental_manager_aidl-cpp",
srcs: [
":incremental_manager_aidl",
],
- imports: [
- "libincremental_aidl",
- "libdataloader_aidl",
+ defaults: ["incremental_default"],
+ shared_libs: [
+ "libincremental_aidl-cpp",
+ "libdataloader_aidl-cpp",
],
- backend: {
- java: {
- sdk_version: "28",
- },
- cpp: {
- enabled: true,
- },
- ndk: {
- enabled: false,
- },
- },
}
// TODO(b/77285514): remove this once the last few hidl interfaces have been
@@ -1311,7 +1304,7 @@
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],
- libs: [ "unsupportedappusage" ],
+ libs: ["unsupportedappusage"],
dxflags: ["--core-library"],
installable: false,
@@ -1452,6 +1445,7 @@
],
libs: [
"framework-annotations-lib",
+ "framework-connectivity",
"unsupportedappusage",
],
visibility: [
@@ -1529,4 +1523,5 @@
":protolog-common-src",
],
}
+
// protolog end
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 30ed7de..175fb38 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,6 @@
[Builtin Hooks]
clang_format = true
+bpfmt = true
[Builtin Hooks Options]
# Only turn on clang-format check for the following subfolders.
@@ -15,7 +16,7 @@
services/incremental/
tests/
tools/
-
+bpfmt = -d
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 4bd524f..bff222e 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -58,6 +58,9 @@
local_include_dirs: [
"apex/media/aidl/stable",
"media/aidl",
+ // TODO: move to include-dirs for packages/modules/Connectivity when this moves out of
+ // frameworks/base
+ "packages/Connectivity/framework/aidl-export",
"telephony/java",
],
include_dirs: ["frameworks/av/aidl"],
@@ -310,6 +313,7 @@
"art.module.public.api.stubs",
"conscrypt.module.public.api.stubs",
"framework-appsearch.stubs",
+ "framework-connectivity.stubs",
"framework-graphics.stubs",
"framework-media.stubs",
"framework-mediaprovider.stubs",
@@ -334,6 +338,7 @@
"art.module.public.api.stubs",
"conscrypt.module.public.api.stubs",
"framework-appsearch.stubs.system",
+ "framework-connectivity.stubs.system",
"framework-graphics.stubs.system",
"framework-media.stubs.system",
"framework-mediaprovider.stubs.system",
@@ -374,6 +379,7 @@
"art.module.public.api.stubs",
"conscrypt.module.public.api.stubs",
"framework-appsearch.stubs.system",
+ "framework-connectivity.stubs.system",
"framework-graphics.stubs.system",
"framework-media.stubs.system",
"framework-mediaprovider.stubs.system",
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index cc79f6b..168c7c2 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -148,7 +148,7 @@
method public void remove(@NonNull android.app.appsearch.RemoveByUriRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
method public void remove(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
method public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
- method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
+ method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
}
@@ -217,7 +217,7 @@
public class GlobalSearchSession implements java.io.Closeable {
method public void close();
- method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
+ method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
}
public class PackageIdentifier {
@@ -287,7 +287,7 @@
public class SearchResults implements java.io.Closeable {
method public void close();
- method public void getNextPage(@NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.util.List<android.app.appsearch.SearchResult>>>);
+ method public void getNextPage(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.util.List<android.app.appsearch.SearchResult>>>);
}
public final class SearchSpec {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 54f3350..24cc60e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -395,21 +395,15 @@
* @param queryExpression query string to search.
* @param searchSpec spec for setting document filters, adding projection, setting term match
* type, etc.
- * @param executor Executor on which to invoke the callback of the following request
- * {@link SearchResults#getNextPage}.
* @return a {@link SearchResults} object for retrieved matched documents.
*/
@NonNull
- public SearchResults search(
- @NonNull String queryExpression,
- @NonNull SearchSpec searchSpec,
- @NonNull @CallbackExecutor Executor executor) {
+ public SearchResults search(@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
Objects.requireNonNull(queryExpression);
Objects.requireNonNull(searchSpec);
- Objects.requireNonNull(executor);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
return new SearchResults(mService, mPackageName, mDatabaseName, queryExpression,
- searchSpec, mUserId, executor);
+ searchSpec, mUserId);
}
/**
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index 93b102b..8dd9dc1 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -106,21 +106,15 @@
* @param queryExpression query string to search.
* @param searchSpec spec for setting document filters, adding projection, setting term match
* type, etc.
- * @param executor Executor on which to invoke the callback of the following request
- * {@link SearchResults#getNextPage}.
* @return a {@link SearchResults} object for retrieved matched documents.
*/
@NonNull
- public SearchResults search(
- @NonNull String queryExpression,
- @NonNull SearchSpec searchSpec,
- @NonNull @CallbackExecutor Executor executor) {
+ public SearchResults search(@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
Objects.requireNonNull(queryExpression);
Objects.requireNonNull(searchSpec);
- Objects.requireNonNull(executor);
Preconditions.checkState(!mIsClosed, "GlobalSearchSession has already been closed");
return new SearchResults(mService, mPackageName, /*databaseName=*/null, queryExpression,
- searchSpec, mUserId, executor);
+ searchSpec, mUserId);
}
/** Closes the {@link GlobalSearchSession}. */
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index e9e978e..531c984 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -65,8 +65,6 @@
@UserIdInt
private final int mUserId;
- private final Executor mExecutor;
-
private long mNextPageToken;
private boolean mIsFirstLoad = true;
@@ -79,15 +77,13 @@
@Nullable String databaseName,
@NonNull String queryExpression,
@NonNull SearchSpec searchSpec,
- @UserIdInt int userId,
- @NonNull @CallbackExecutor Executor executor) {
+ @UserIdInt int userId) {
mService = Objects.requireNonNull(service);
mPackageName = packageName;
mDatabaseName = databaseName;
mQueryExpression = Objects.requireNonNull(queryExpression);
mSearchSpec = Objects.requireNonNull(searchSpec);
mUserId = userId;
- mExecutor = Objects.requireNonNull(executor);
}
/**
@@ -98,9 +94,14 @@
* <p>Continue calling this method to access results until it returns an empty list, signifying
* there are no more results.
*
+ * @param executor Executor on which to invoke the callback.
* @param callback Callback to receive the pending result of performing this operation.
*/
- public void getNextPage(@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+ public void getNextPage(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
Preconditions.checkState(!mIsClosed, "SearchResults has already been closed");
try {
if (mIsFirstLoad) {
@@ -108,14 +109,14 @@
if (mDatabaseName == null) {
// Global query, there's no one package-database combination to check.
mService.globalQuery(mPackageName, mQueryExpression,
- mSearchSpec.getBundle(), mUserId, wrapCallback(callback));
+ mSearchSpec.getBundle(), mUserId, wrapCallback(executor, callback));
} else {
// Normal local query, pass in specified database.
mService.query(mPackageName, mDatabaseName, mQueryExpression,
- mSearchSpec.getBundle(), mUserId, wrapCallback(callback));
+ mSearchSpec.getBundle(), mUserId, wrapCallback(executor, callback));
}
} else {
- mService.getNextPage(mNextPageToken, mUserId, wrapCallback(callback));
+ mService.getNextPage(mNextPageToken, mUserId, wrapCallback(executor, callback));
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -135,10 +136,11 @@
}
private IAppSearchResultCallback wrapCallback(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
return new IAppSearchResultCallback.Stub() {
public void onResult(AppSearchResult result) {
- mExecutor.execute(() -> invokeCallback(result, callback));
+ executor.execute(() -> invokeCallback(result, callback));
}
};
}
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
index afa633a..9ef6e0b 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
@@ -124,8 +124,7 @@
@NonNull
public SearchResultsShim search(
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
- SearchResults searchResults =
- mAppSearchSession.search(queryExpression, searchSpec, mExecutor);
+ SearchResults searchResults = mAppSearchSession.search(queryExpression, searchSpec);
return new SearchResultsShimImpl(searchResults, mExecutor);
}
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
index 6595d8d..69a4c18 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
@@ -75,8 +75,7 @@
@Override
public SearchResultsShim search(
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
- SearchResults searchResults =
- mGlobalSearchSession.search(queryExpression, searchSpec, mExecutor);
+ SearchResults searchResults = mGlobalSearchSession.search(queryExpression, searchSpec);
return new SearchResultsShimImpl(searchResults, mExecutor);
}
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
index 75add81..5f26e8c 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
@@ -47,7 +47,7 @@
@NonNull
public ListenableFuture<List<SearchResult>> getNextPage() {
SettableFuture<AppSearchResult<List<SearchResult>>> future = SettableFuture.create();
- mSearchResults.getNextPage(future::set);
+ mSearchResults.getNextPage(mExecutor, future::set);
return Futures.transform(future, AppSearchResult::getResultValue, mExecutor);
}
diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
index 5693abe..43d4873 100644
--- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
+++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
@@ -43,10 +43,10 @@
boolean isPowerSaveWhitelistApp(String name);
@UnsupportedAppUsage(maxTargetSdk = 30,
publicAlternatives = "Use SystemApi {@code PowerWhitelistManager#whitelistAppTemporarily(String, int, String)}.")
- void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
- long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
- long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
- long whitelistAppTemporarily(String name, int userId, String reason);
+ void addPowerSaveTempWhitelistApp(String name, long duration, int userId, int reasonCode, String reason);
+ long addPowerSaveTempWhitelistAppForMms(String name, int userId, int reasonCode, String reason);
+ long addPowerSaveTempWhitelistAppForSms(String name, int userId, int reasonCode, String reason);
+ long whitelistAppTemporarily(String name, int userId, int reasonCode, String reason);
void exitIdle(String reason);
int setPreIdleTimeoutMode(int Mode);
void resetPreIdleTimeoutMode();
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index df0e157..df690d0 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -16,8 +16,16 @@
package android.os;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -94,6 +102,239 @@
@Retention(RetentionPolicy.SOURCE)
public @interface TempAllowListType {}
+ /* Reason code for BG-FGS-launch. */
+ /**
+ * BG-FGS-launch is denied.
+ * @hide
+ */
+ public static final int REASON_DENIED = -1;
+ /**
+ * The default reason code if reason is unknown.
+ */
+ public static final int REASON_UNKNOWN = 0;
+ /**
+ * Use REASON_OTHER if there is no better choice.
+ */
+ public static final int REASON_OTHER = 1;
+ /** @hide */
+ public static final int REASON_PROC_STATE_PERSISTENT = 10;
+ /** @hide */
+ public static final int REASON_PROC_STATE_PERSISTENT_UI = 11;
+ /** @hide */
+ public static final int REASON_PROC_STATE_TOP = 12;
+ /** @hide */
+ public static final int REASON_PROC_STATE_BTOP = 13;
+ /** @hide */
+ public static final int REASON_PROC_STATE_FGS = 14;
+ /** @hide */
+ public static final int REASON_PROC_STATE_BFGS = 15;
+ /** @hide */
+ public static final int REASON_UID_VISIBLE = 50;
+ /** @hide */
+ public static final int REASON_SYSTEM_UID = 51;
+ /** @hide */
+ public static final int REASON_ACTIVITY_STARTER = 52;
+ /** @hide */
+ public static final int REASON_START_ACTIVITY_FLAG = 53;
+ /** @hide */
+ public static final int REASON_FGS_BINDING = 54;
+ /** @hide */
+ public static final int REASON_DEVICE_OWNER = 55;
+ /** @hide */
+ public static final int REASON_PROFILE_OWNER = 56;
+ /** @hide */
+ public static final int REASON_COMPANION_DEVICE_MANAGER = 57;
+ /**
+ * START_ACTIVITIES_FROM_BACKGROUND permission.
+ * @hide
+ */
+ public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = 58;
+ /**
+ * START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
+ * @hide
+ */
+ public static final int REASON_BACKGROUND_FGS_PERMISSION = 59;
+ /** @hide */
+ public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 60;
+ /** @hide */
+ public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION = 61;
+ /** @hide */
+ public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION = 62;
+ /** @hide */
+ public static final int REASON_DEVICE_DEMO_MODE = 63;
+ /** @hide */
+ public static final int REASON_EXEMPTED_PACKAGE = 64;
+ /** @hide */
+ public static final int REASON_ALLOWLISTED_PACKAGE = 65;
+ /**
+ * If it's because of a role,
+ * @hide
+ */
+ public static final int REASON_APPOP = 66;
+
+ /* BG-FGS-launch is allowed by temp-allowlist or system-allowlist.
+ Reason code for temp and system allowlist starts here.
+ */
+ public static final int REASON_GEOFENCING = 100;
+ public static final int REASON_PUSH_MESSAGING = 101;
+ public static final int REASON_ACTIVITY_RECOGNITION = 102;
+
+ /**
+ * Broadcast ACTION_BOOT_COMPLETED.
+ * @hide
+ */
+ public static final int REASON_BOOT_COMPLETED = 103;
+ /**
+ * Broadcast ACTION_PRE_BOOT_COMPLETED.
+ * @hide
+ */
+ public static final int REASON_PRE_BOOT_COMPLETED = 104;
+
+ /**
+ * Broadcast ACTION_LOCKED_BOOT_COMPLETED.
+ * @hide
+ */
+ public static final int REASON_LOCKED_BOOT_COMPLETED = 105;
+ /**
+ * Device idle system allowlist, including EXCEPT-IDLE
+ * @hide
+ */
+ public static final int REASON_SYSTEM_ALLOW_LISTED = 106;
+ /** @hide */
+ public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 107;
+ /**
+ * AlarmManagerService.
+ * @hide
+ */
+ public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 108;
+ /**
+ * ActiveServices.
+ * @hide
+ */
+ public static final int REASON_SERVICE_LAUNCH = 109;
+ /**
+ * KeyChainSystemService.
+ * @hide
+ */
+ public static final int REASON_KEY_CHAIN = 110;
+ /**
+ * PackageManagerService.
+ * @hide
+ */
+ public static final int REASON_PACKAGE_VERIFIER = 111;
+ /**
+ * SyncManager.
+ * @hide
+ */
+ public static final int REASON_SYNC_MANAGER = 112;
+ /**
+ * DomainVerificationProxyV1.
+ * @hide
+ */
+ public static final int REASON_DOMAIN_VERIFICATION_V1 = 113;
+ /**
+ * DomainVerificationProxyV2.
+ * @hide
+ */
+ public static final int REASON_DOMAIN_VERIFICATION_V2 = 114;
+ /** @hide */
+ public static final int REASON_VPN = 115;
+ /**
+ * NotificationManagerService.
+ * @hide
+ */
+ public static final int REASON_NOTIFICATION_SERVICE = 116;
+ /**
+ * Broadcast ACTION_MY_PACKAGE_REPLACED.
+ * @hide
+ */
+ public static final int REASON_PACKAGE_REPLACED = 117;
+ /**
+ * LocationProviderManager.
+ * @hide
+ */
+ public static final int REASON_LOCATION_PROVIDER = 118;
+ /**
+ * MediaButtonReceiver.
+ * @hide
+ */
+ public static final int REASON_MEDIA_BUTTON = 119;
+ /**
+ * InboundSmsHandler.
+ * @hide
+ */
+ public static final int REASON_EVENT_SMS = 120;
+ /**
+ * InboundSmsHandler.
+ * @hide
+ */
+ public static final int REASON_EVENT_MMS = 121;
+ /**
+ * Shell app.
+ * @hide
+ */
+ public static final int REASON_SHELL = 122;
+
+ /**
+ * The list of BG-FGS-Launch and temp-allowlist reason code.
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "REASON_" }, value = {
+ // BG-FGS-Launch reasons.
+ REASON_DENIED,
+ REASON_UNKNOWN,
+ REASON_OTHER,
+ REASON_PROC_STATE_PERSISTENT,
+ REASON_PROC_STATE_PERSISTENT_UI,
+ REASON_PROC_STATE_TOP,
+ REASON_PROC_STATE_BTOP,
+ REASON_PROC_STATE_FGS,
+ REASON_PROC_STATE_BFGS,
+ REASON_UID_VISIBLE,
+ REASON_SYSTEM_UID,
+ REASON_ACTIVITY_STARTER,
+ REASON_START_ACTIVITY_FLAG,
+ REASON_FGS_BINDING,
+ REASON_DEVICE_OWNER,
+ REASON_PROFILE_OWNER,
+ REASON_COMPANION_DEVICE_MANAGER,
+ REASON_BACKGROUND_ACTIVITY_PERMISSION,
+ REASON_BACKGROUND_FGS_PERMISSION,
+ REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
+ REASON_INSTR_BACKGROUND_FGS_PERMISSION,
+ REASON_SYSTEM_ALERT_WINDOW_PERMISSION,
+ REASON_DEVICE_DEMO_MODE,
+ REASON_EXEMPTED_PACKAGE,
+ REASON_ALLOWLISTED_PACKAGE,
+ REASON_APPOP,
+ // temp and system allowlist reasons.
+ REASON_GEOFENCING,
+ REASON_PUSH_MESSAGING,
+ REASON_ACTIVITY_RECOGNITION,
+ REASON_BOOT_COMPLETED,
+ REASON_PRE_BOOT_COMPLETED,
+ REASON_LOCKED_BOOT_COMPLETED,
+ REASON_SYSTEM_ALLOW_LISTED,
+ REASON_ALARM_MANAGER_ALARM_CLOCK,
+ REASON_ALARM_MANAGER_WHILE_IDLE,
+ REASON_SERVICE_LAUNCH,
+ REASON_KEY_CHAIN,
+ REASON_PACKAGE_VERIFIER,
+ REASON_SYNC_MANAGER,
+ REASON_DOMAIN_VERIFICATION_V1,
+ REASON_DOMAIN_VERIFICATION_V2,
+ REASON_VPN,
+ REASON_NOTIFICATION_SERVICE,
+ REASON_PACKAGE_REPLACED,
+ REASON_LOCATION_PROVIDER,
+ REASON_MEDIA_BUTTON,
+ REASON_EVENT_SMS,
+ REASON_EVENT_MMS,
+ REASON_SHELL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReasonCode {}
+
/**
* @hide
*/
@@ -184,19 +425,34 @@
*
* @param packageName The package to add to the temp whitelist
* @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
+ * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
+ * @param reason a optional human readable reason string, could be null or empty string.
*/
@RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
- public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
- String reason = "from:" + UserHandle.formatUid(Binder.getCallingUid());
+ public void whitelistAppTemporarily(@NonNull String packageName, long durationMs,
+ @ReasonCode int reasonCode, @Nullable String reason) {
try {
mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(),
- reason);
+ reasonCode, reason);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
+ * Add an app to the temporary whitelist for a short amount of time.
+ *
+ * @param packageName The package to add to the temp whitelist
+ * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
+ * @deprecated Use {@link #whitelistAppTemporarily(String, long, int, String)} instead
+ */
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+ public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
+ whitelistAppTemporarily(packageName, durationMs, REASON_UNKNOWN, packageName);
+ }
+
+ /**
* Add an app to the temporary whitelist for a short amount of time for a specific reason. The
* temporary whitelist is kept separately from the permanent whitelist and apps are
* automatically removed from the temporary whitelist after a predetermined amount of time.
@@ -204,27 +460,179 @@
* @param packageName The package to add to the temp whitelist
* @param event The reason to add the app to the temp whitelist
* @param reason A human-readable reason explaining why the app is temp whitelisted. Only
- * used for logging purposes
+ * used for logging purposes. Could be null or empty string.
+ * @return The duration (in milliseconds) that the app is whitelisted for
+ * @deprecated Use {@link #whitelistAppTemporarilyForEvent(String, int, int, String)} instead
+ */
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+ public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
+ @WhitelistEvent int event, @Nullable String reason) {
+ return whitelistAppTemporarilyForEvent(packageName, event, REASON_UNKNOWN, reason);
+ }
+
+ /**
+ * Add an app to the temporary whitelist for a short amount of time for a specific reason. The
+ * temporary whitelist is kept separately from the permanent whitelist and apps are
+ * automatically removed from the temporary whitelist after a predetermined amount of time.
+ *
+ * @param packageName The package to add to the temp whitelist
+ * @param event The reason to add the app to the temp whitelist
+ * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
+ * @param reason A human-readable reason explaining why the app is temp whitelisted. Only
+ * used for logging purposes. Could be null or empty string.
* @return The duration (in milliseconds) that the app is whitelisted for
*/
@RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
- @WhitelistEvent int event, @NonNull String reason) {
+ @WhitelistEvent int event, @ReasonCode int reasonCode, @Nullable String reason) {
try {
switch (event) {
case EVENT_MMS:
return mService.addPowerSaveTempWhitelistAppForMms(
- packageName, mContext.getUserId(), reason);
+ packageName, mContext.getUserId(), reasonCode, reason);
case EVENT_SMS:
return mService.addPowerSaveTempWhitelistAppForSms(
- packageName, mContext.getUserId(), reason);
+ packageName, mContext.getUserId(), reasonCode, reason);
case EVENT_UNSPECIFIED:
default:
return mService.whitelistAppTemporarily(
- packageName, mContext.getUserId(), reason);
+ packageName, mContext.getUserId(), reasonCode, reason);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * @hide
+ */
+ public static @ReasonCode int getReasonCodeFromProcState(int procState) {
+ if (procState <= PROCESS_STATE_PERSISTENT) {
+ return REASON_PROC_STATE_PERSISTENT;
+ } else if (procState <= PROCESS_STATE_PERSISTENT_UI) {
+ return REASON_PROC_STATE_PERSISTENT_UI;
+ } else if (procState <= PROCESS_STATE_TOP) {
+ return REASON_PROC_STATE_TOP;
+ } else if (procState <= PROCESS_STATE_BOUND_TOP) {
+ return REASON_PROC_STATE_BTOP;
+ } else if (procState <= PROCESS_STATE_FOREGROUND_SERVICE) {
+ return REASON_PROC_STATE_FGS;
+ } else if (procState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ return REASON_PROC_STATE_BFGS;
+ } else {
+ return REASON_DENIED;
+ }
+ }
+
+ /**
+ * Return string name of the integer reason code.
+ * @hide
+ * @param reasonCode
+ * @return string name of the reason code.
+ */
+ public static String reasonCodeToString(@ReasonCode int reasonCode) {
+ switch (reasonCode) {
+ case REASON_DENIED:
+ return "DENIED";
+ case REASON_UNKNOWN:
+ return "UNKNOWN";
+ case REASON_OTHER:
+ return "OTHER";
+ case REASON_PROC_STATE_PERSISTENT:
+ return "PROC_STATE_PERSISTENT";
+ case REASON_PROC_STATE_PERSISTENT_UI:
+ return "PROC_STATE_PERSISTENT_UI";
+ case REASON_PROC_STATE_TOP:
+ return "PROC_STATE_TOP";
+ case REASON_PROC_STATE_BTOP:
+ return "PROC_STATE_BTOP";
+ case REASON_PROC_STATE_FGS:
+ return "PROC_STATE_FGS";
+ case REASON_PROC_STATE_BFGS:
+ return "PROC_STATE_BFGS";
+ case REASON_UID_VISIBLE:
+ return "UID_VISIBLE";
+ case REASON_SYSTEM_UID:
+ return "SYSTEM_UID";
+ case REASON_ACTIVITY_STARTER:
+ return "ACTIVITY_STARTER";
+ case REASON_START_ACTIVITY_FLAG:
+ return "START_ACTIVITY_FLAG";
+ case REASON_FGS_BINDING:
+ return "FGS_BINDING";
+ case REASON_DEVICE_OWNER:
+ return "DEVICE_OWNER";
+ case REASON_PROFILE_OWNER:
+ return "PROFILE_OWNER";
+ case REASON_COMPANION_DEVICE_MANAGER:
+ return "COMPANION_DEVICE_MANAGER";
+ case REASON_BACKGROUND_ACTIVITY_PERMISSION:
+ return "BACKGROUND_ACTIVITY_PERMISSION";
+ case REASON_BACKGROUND_FGS_PERMISSION:
+ return "BACKGROUND_FGS_PERMISSION";
+ case REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
+ return "INSTR_BACKGROUND_ACTIVITY_PERMISSION";
+ case REASON_INSTR_BACKGROUND_FGS_PERMISSION:
+ return "INSTR_BACKGROUND_FGS_PERMISSION";
+ case REASON_SYSTEM_ALERT_WINDOW_PERMISSION:
+ return "SYSTEM_ALERT_WINDOW_PERMISSION";
+ case REASON_DEVICE_DEMO_MODE:
+ return "DEVICE_DEMO_MODE";
+ case REASON_EXEMPTED_PACKAGE:
+ return "EXEMPTED_PACKAGE";
+ case REASON_ALLOWLISTED_PACKAGE:
+ return "ALLOWLISTED_PACKAGE";
+ case REASON_APPOP:
+ return "APPOP";
+ case REASON_GEOFENCING:
+ return "GEOFENCING";
+ case REASON_PUSH_MESSAGING:
+ return "PUSH_MESSAGING";
+ case REASON_ACTIVITY_RECOGNITION:
+ return "ACTIVITY_RECOGNITION";
+ case REASON_BOOT_COMPLETED:
+ return "BOOT_COMPLETED";
+ case REASON_PRE_BOOT_COMPLETED:
+ return "PRE_BOOT_COMPLETED";
+ case REASON_LOCKED_BOOT_COMPLETED:
+ return "LOCKED_BOOT_COMPLETED";
+ case REASON_SYSTEM_ALLOW_LISTED:
+ return "SYSTEM_ALLOW_LISTED";
+ case REASON_ALARM_MANAGER_ALARM_CLOCK:
+ return "ALARM_MANAGER_ALARM_CLOCK";
+ case REASON_ALARM_MANAGER_WHILE_IDLE:
+ return "ALARM_MANAGER_WHILE_IDLE";
+ case REASON_SERVICE_LAUNCH:
+ return "SERVICE_LAUNCH";
+ case REASON_KEY_CHAIN:
+ return "KEY_CHAIN";
+ case REASON_PACKAGE_VERIFIER:
+ return "PACKAGE_VERIFIER";
+ case REASON_SYNC_MANAGER:
+ return "SYNC_MANAGER";
+ case REASON_DOMAIN_VERIFICATION_V1:
+ return "DOMAIN_VERIFICATION_V1";
+ case REASON_DOMAIN_VERIFICATION_V2:
+ return "DOMAIN_VERIFICATION_V2";
+ case REASON_VPN:
+ return "VPN";
+ case REASON_NOTIFICATION_SERVICE:
+ return "NOTIFICATION_SERVICE";
+ case REASON_PACKAGE_REPLACED:
+ return "PACKAGE_REPLACED";
+ case REASON_LOCATION_PROVIDER:
+ return "LOCATION_PROVIDER";
+ case REASON_MEDIA_BUTTON:
+ return "MEDIA_BUTTON";
+ case REASON_EVENT_SMS:
+ return "EVENT_SMS";
+ case REASON_EVENT_MMS:
+ return "EVENT_MMS";
+ case REASON_SHELL:
+ return "SHELL";
+ default:
+ return "(unknown:" + reasonCode + ")";
+ }
+ }
}
diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
index e045b0f..5e5717d11 100644
--- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
@@ -16,6 +16,8 @@
package com.android.server;
+import android.annotation.Nullable;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.PowerWhitelistManager.TempAllowListType;
import com.android.server.deviceidle.IDeviceIdleConstraint;
@@ -34,6 +36,10 @@
void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
long duration, int userId, boolean sync, String reason);
+ void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
+ long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+ @Nullable String reason);
+
/**
* Called by ActivityManagerService to directly add UID to DeviceIdleController's temp
* allowlist.
@@ -41,11 +47,12 @@
* @param duration duration in milliseconds
* @param type temp allowlist type defined at {@link TempAllowListType}
* @param sync
+ * @param reasonCode one of {@link ReasonCode}
* @param reason
*/
void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
- @TempAllowListType int type, boolean sync,
- String reason);
+ @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
+ @Nullable String reason);
// duration in milliseconds
long getNotificationAllowlistDuration();
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 8f7f705..ac28e82 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -16,12 +16,17 @@
package com.android.server;
+import static android.os.PowerWhitelistManager.REASON_SHELL;
+import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.Process.INVALID_UID;
+
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
-import android.app.BroadcastOptions;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -56,6 +61,7 @@
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.PowerWhitelistManager.TempAllowListType;
import android.os.Process;
import android.os.RemoteException;
@@ -1838,31 +1844,34 @@
}
@Override
- public long whitelistAppTemporarily(String packageName, int userId, String reason)
- throws RemoteException {
+ public long whitelistAppTemporarily(String packageName, int userId,
+ @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
// At least 10 seconds.
long durationMs = Math.max(10_000L, mConstants.MAX_TEMP_APP_ALLOWLIST_DURATION_MS / 2);
- addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reason);
+ addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reasonCode,
+ reason);
return durationMs;
}
@Override
- public void addPowerSaveTempWhitelistApp(String packageName, long duration,
- int userId, String reason) throws RemoteException {
- addPowerSaveTempAllowlistAppChecked(packageName, duration, userId, reason);
+ public void addPowerSaveTempWhitelistApp(String packageName, long duration, int userId,
+ @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
+ addPowerSaveTempAllowlistAppChecked(packageName, duration, userId, reasonCode, reason);
}
- @Override public long addPowerSaveTempWhitelistAppForMms(String packageName,
- int userId, String reason) throws RemoteException {
+ @Override public long addPowerSaveTempWhitelistAppForMms(String packageName, int userId,
+ @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
long durationMs = mConstants.MMS_TEMP_APP_ALLOWLIST_DURATION_MS;
- addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reason);
+ addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reasonCode,
+ reason);
return durationMs;
}
- @Override public long addPowerSaveTempWhitelistAppForSms(String packageName,
- int userId, String reason) throws RemoteException {
+ @Override public long addPowerSaveTempWhitelistAppForSms(String packageName, int userId,
+ @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
long durationMs = mConstants.SMS_TEMP_APP_ALLOWLIST_DURATION_MS;
- addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reason);
+ addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reasonCode,
+ reason);
return durationMs;
}
@@ -1934,18 +1943,29 @@
}
// duration in milliseconds
+ @Deprecated
@Override
public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
- long duration, int userId, boolean sync, String reason) {
+ long duration, int userId, boolean sync, @Nullable String reason) {
addPowerSaveTempAllowlistAppInternal(callingUid, packageName, duration,
- userId, sync, reason);
+ userId, sync, REASON_UNKNOWN, reason);
+ }
+
+ @Override
+ public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
+ long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+ @Nullable String reason) {
+ addPowerSaveTempAllowlistAppInternal(callingUid, packageName, duration,
+ userId, sync, reasonCode, reason);
}
// duration in milliseconds
@Override
public void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
- @TempAllowListType int type, boolean sync, String reason) {
- addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, type, sync, reason);
+ @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
+ @Nullable String reason) {
+ addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, type, sync,
+ reasonCode, reason);
}
// duration in milliseconds
@@ -2293,7 +2313,7 @@
filter.addAction(Intent.ACTION_SCREEN_ON);
getContext().registerReceiver(mInteractivityReceiver, filter);
- mLocalActivityManager.setDeviceIdleWhitelist(
+ mLocalActivityManager.setDeviceIdleAllowlist(
mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
@@ -2671,7 +2691,8 @@
}
void addPowerSaveTempAllowlistAppChecked(String packageName, long duration,
- int userId, String reason) throws RemoteException {
+ int userId, @ReasonCode int reasonCode, @Nullable String reason)
+ throws RemoteException {
getContext().enforceCallingPermission(
Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
"No permission to change device idle whitelist");
@@ -2686,7 +2707,7 @@
final long token = Binder.clearCallingIdentity();
try {
addPowerSaveTempAllowlistAppInternal(callingUid,
- packageName, duration, userId, true, reason);
+ packageName, duration, userId, true, reasonCode, reason);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2718,12 +2739,12 @@
* app an exemption to access network and acquire wakelocks.
*/
void addPowerSaveTempAllowlistAppInternal(int callingUid, String packageName,
- long duration, int userId, boolean sync, String reason) {
+ long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+ @Nullable String reason) {
try {
int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration,
- BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED, sync,
- reason);
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, sync, reasonCode, reason);
} catch (NameNotFoundException e) {
}
}
@@ -2733,7 +2754,8 @@
* app an exemption to access network and acquire wakelocks.
*/
void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int uid,
- long duration, @TempAllowListType int type, boolean sync, String reason) {
+ long duration, @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
+ @Nullable String reason) {
final long timeNow = SystemClock.elapsedRealtime();
boolean informWhitelistChanged = false;
int appId = UserHandle.getAppId(uid);
@@ -2765,7 +2787,8 @@
} catch (RemoteException e) {
}
postTempActiveTimeoutMessage(uid, duration);
- updateTempWhitelistAppIdsLocked(uid, true, duration, type);
+ updateTempWhitelistAppIdsLocked(uid, true, duration, type, reasonCode,
+ reason, callingUid);
if (sync) {
informWhitelistChanged = true;
} else {
@@ -2844,12 +2867,13 @@
}
@GuardedBy("this")
- private void onAppRemovedFromTempWhitelistLocked(int uid, String reason) {
+ private void onAppRemovedFromTempWhitelistLocked(int uid, @Nullable String reason) {
if (DEBUG) {
Slog.d(TAG, "Removing uid " + uid + " from temp whitelist");
}
final int appId = UserHandle.getAppId(uid);
- updateTempWhitelistAppIdsLocked(uid, false, 0, 0);
+ updateTempWhitelistAppIdsLocked(uid, false, 0, 0, REASON_UNKNOWN,
+ reason, INVALID_UID);
mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED_TO_NPMS, appId, 0)
.sendToTarget();
reportTempWhitelistChangedLocked(uid, false);
@@ -3860,7 +3884,7 @@
mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
if (mLocalActivityManager != null) {
- mLocalActivityManager.setDeviceIdleWhitelist(
+ mLocalActivityManager.setDeviceIdleAllowlist(
mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
}
if (mLocalPowerManager != null) {
@@ -3880,9 +3904,14 @@
* @param durationMs duration in milliseconds to add to temp allowlist, only valid when
* param adding is true.
* @param type temp allowlist type defined at {@link TempAllowListType}
+ * @prama reasonCode one of {@Link ReasonCode}
+ * @param reason A human-readable reason for logging purposes.
+ * @param callingUid the callingUid that setup this temp-allowlist, only valid when param adding
+ * is true.
*/
private void updateTempWhitelistAppIdsLocked(int uid, boolean adding, long durationMs,
- @TempAllowListType int type) {
+ @TempAllowListType int type, @ReasonCode int reasonCode, @Nullable String reason,
+ int callingUid) {
final int size = mTempWhitelistAppIdEndTimes.size();
if (mTempWhitelistAppIdArray.length != size) {
mTempWhitelistAppIdArray = new int[size];
@@ -3895,8 +3924,8 @@
Slog.d(TAG, "Setting activity manager temp whitelist to "
+ Arrays.toString(mTempWhitelistAppIdArray));
}
- mLocalActivityManager.updateDeviceIdleTempWhitelist(mTempWhitelistAppIdArray, uid,
- adding, durationMs, type);
+ mLocalActivityManager.updateDeviceIdleTempAllowlist(mTempWhitelistAppIdArray, uid,
+ adding, durationMs, type, reasonCode, reason, callingUid);
}
if (mLocalPowerManager != null) {
if (DEBUG) {
@@ -4428,7 +4457,8 @@
if (removePkg) {
removePowerSaveTempAllowlistAppChecked(arg, shell.userId);
} else {
- addPowerSaveTempAllowlistAppChecked(arg, duration, shell.userId, "shell");
+ addPowerSaveTempAllowlistAppChecked(arg, duration, shell.userId,
+ REASON_SHELL, "shell");
}
} catch (Exception e) {
pw.println("Failed: " + e);
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 ea73369..2b2918c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -28,6 +28,8 @@
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
import static android.os.UserHandle.USER_SYSTEM;
@@ -524,10 +526,12 @@
if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {
mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;
- mOptsWithFgs.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION);
- mOptsWithoutFgs.setTemporaryAppWhitelistDuration(
+ mOptsWithFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_ALARM_MANAGER_WHILE_IDLE, "");
+ mOptsWithoutFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
- ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+ REASON_ALARM_MANAGER_WHILE_IDLE, "");
}
}
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 af97715..e8e2c27 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -753,13 +753,22 @@
return null;
}
+ // We're over the minimum guaranteed runtime. Stop the job if we're over config limits,
+ // there are pending jobs that could replace this one, or the device state is not conducive
+ // to long runs.
+
+ if (mPowerManager.isPowerSaveMode()) {
+ return "battery saver";
+ }
+ if (mPowerManager.isDeviceIdleMode()) {
+ return "deep doze";
+ }
+
// Update config in case memory usage has changed significantly.
updateCounterConfigLocked();
@WorkType final int workType = context.getRunningJobWorkType();
- // We're over the minimum guaranteed runtime. Stop the job if we're over config limits or
- // there are pending jobs that could replace this one.
if (mRunningJobs.size() > mWorkTypeConfig.getMaxTotal()
|| mWorkCountTracker.isOverTypeLimit(workType)) {
return "too many jobs running";
@@ -786,13 +795,6 @@
return "blocking " + workTypeToString(workType) + " queue";
}
}
-
- if (mPowerManager.isPowerSaveMode()) {
- return "battery saver";
- }
- if (mPowerManager.isDeviceIdleMode()) {
- return "deep doze";
- }
}
// Easy check. If there are pending jobs of the same work type, then we know that
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 fc2a409..8bb03e9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -887,8 +887,10 @@
}
@Override
- public void onUserStarting(@NonNull TargetUser user) {
+ public void onUserUnlocked(@NonNull TargetUser user) {
synchronized (mLock) {
+ // Note that the user has started after its unlocked instead of when the user
+ // actually starts because the storage won't be decrypted until unlock.
mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier());
}
// Let's kick any outstanding jobs for this user.
@@ -896,12 +898,6 @@
}
@Override
- public void onUserUnlocking(@NonNull TargetUser user) {
- // Let's kick any outstanding jobs for this user.
- mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
- }
-
- @Override
public void onUserStopping(@NonNull TargetUser user) {
synchronized (mLock) {
mStartedUsers = ArrayUtils.removeInt(mStartedUsers, user.getUserIdentifier());
@@ -2297,7 +2293,8 @@
/** Returns the maximum amount of time this job could run for. */
public long getMaxJobExecutionTimeMs(JobStatus job) {
synchronized (mLock) {
- return mQuotaController.getMaxJobExecutionTimeMsLocked(job);
+ return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked(job));
}
}
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 2faa836..b70e68b 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
@@ -995,12 +995,18 @@
if (standbyBucket == NEVER_INDEX) {
return 0;
}
+
List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+ final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
if (sessions == null || sessions.size() == 0) {
+ // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can
+ // essentially run until they reach the maximum limit.
+ if (stats.windowSizeMs == mAllowedTimePerPeriodMs) {
+ return mMaxExecutionTimeMs;
+ }
return mAllowedTimePerPeriodMs;
}
- final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
final long startWindowElapsed = nowElapsed - stats.windowSizeMs;
final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS;
final long allowedTimeRemainingMs = mAllowedTimePerPeriodMs - stats.executionTimeInWindowMs;
diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
index 3d50d14..fb3172b 100644
--- a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
+++ b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
@@ -15,7 +15,17 @@
*/
package android.media;
+import android.media.Session2Token;
+import android.media.IMediaCommunicationServiceCallback;
+import android.media.MediaParceledListSlice;
+
/** {@hide} */
interface IMediaCommunicationService {
+ void notifySession2Created(in Session2Token sessionToken);
+ boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
+ MediaParceledListSlice getSession2Tokens(int userId);
+
+ void registerCallback(IMediaCommunicationServiceCallback callback, String packageName);
+ void unregisterCallback(IMediaCommunicationServiceCallback callback);
}
diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl
new file mode 100644
index 0000000..3d5321c
--- /dev/null
+++ b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl
@@ -0,0 +1,26 @@
+/**
+ * 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.media;
+
+import android.media.Session2Token;
+import android.media.MediaParceledListSlice;
+
+/** {@hide} */
+interface IMediaCommunicationServiceCallback {
+ void onSession2Created(in Session2Token token);
+ void onSession2Changed(in MediaParceledListSlice tokens);
+}
+
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index a2366df..1beef40 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -26,6 +26,7 @@
}
public class MediaCommunicationManager {
+ method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
method @IntRange(from=1) public int getVersion();
}
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
index ad9114f..eb6397a1 100644
--- a/apex/media/framework/api/module-lib-current.txt
+++ b/apex/media/framework/api/module-lib-current.txt
@@ -1,6 +1,16 @@
// Signature format: 2.0
package android.media {
+ public class MediaCommunicationManager {
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaCommunicationManager.SessionCallback);
+ method public void unregisterSessionCallback(@NonNull android.media.MediaCommunicationManager.SessionCallback);
+ }
+
+ public static interface MediaCommunicationManager.SessionCallback {
+ method public default void onSession2TokenCreated(@NonNull android.media.Session2Token);
+ method public default void onSession2TokensChanged(@NonNull java.util.List<android.media.Session2Token>);
+ }
+
public class MediaFrameworkInitializer {
method public static void registerServiceWrappers();
method public static void setMediaServiceManager(@NonNull android.media.MediaServiceManager);
diff --git a/apex/media/framework/java/android/media/Controller2Link.java b/apex/media/framework/java/android/media/Controller2Link.java
index 04185e7..8eefec7 100644
--- a/apex/media/framework/java/android/media/Controller2Link.java
+++ b/apex/media/framework/java/android/media/Controller2Link.java
@@ -26,7 +26,7 @@
import java.util.Objects;
/**
- * Handles incoming commands from {@link MediaSession2} to both {@link MediaController2}.
+ * Handles incoming commands from {@link MediaSession2} to {@link MediaController2}.
* @hide
*/
// @SystemApi
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index e686076..9ec25fe 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -15,18 +15,36 @@
*/
package android.media;
+import static android.Manifest.permission.MEDIA_CONTENT_CONTROL;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.CallbackExecutor;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.media.MediaBrowserService;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.modules.utils.build.SdkLevel;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+
/**
* Provides support for interacting with {@link android.media.MediaSession2 MediaSession2s}
* that applications have published to express their ongoing media playback state.
*/
-// TODO: Add notifySession2Created() and sendMessage().
@SystemService(Context.MEDIA_COMMUNICATION_SERVICE)
public class MediaCommunicationManager {
private static final String TAG = "MediaCommunicationManager";
@@ -44,6 +62,13 @@
private final Context mContext;
private final IMediaCommunicationService mService;
+ private final Object mLock = new Object();
+ private final CopyOnWriteArrayList<SessionCallbackRecord> mTokenCallbackRecords =
+ new CopyOnWriteArrayList<>();
+
+ @GuardedBy("mLock")
+ private MediaCommunicationServiceCallbackStub mCallbackStub;
+
/**
* @hide
*/
@@ -64,4 +89,197 @@
public @IntRange(from = 1) int getVersion() {
return CURRENT_VERSION;
}
+
+ /**
+ * Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is
+ * created.
+ * @param token newly created session2 token
+ * @hide
+ */
+ public void notifySession2Created(@NonNull Session2Token token) {
+ Objects.requireNonNull(token, "token shouldn't be null");
+ if (token.getType() != Session2Token.TYPE_SESSION) {
+ throw new IllegalArgumentException("token's type should be TYPE_SESSION");
+ }
+ try {
+ mService.notifySession2Created(token);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Checks whether the remote user is a trusted app.
+ * <p>
+ * An app is trusted if the app holds the
+ * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled
+ * notification listener.
+ *
+ * @param userInfo The remote user info from either
+ * {@link MediaSession#getCurrentControllerInfo()} or
+ * {@link MediaBrowserService#getCurrentBrowserInfo()}.
+ * @return {@code true} if the remote user is trusted or {@code false} otherwise.
+ * @hide
+ */
+ public boolean isTrustedForMediaControl(@NonNull MediaSessionManager.RemoteUserInfo userInfo) {
+ Objects.requireNonNull(userInfo, "userInfo shouldn't be null");
+ if (userInfo.getPackageName() == null) {
+ return false;
+ }
+ try {
+ return mService.isTrusted(
+ userInfo.getPackageName(), userInfo.getPid(), userInfo.getUid());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot communicate with the service.", e);
+ }
+ return false;
+ }
+
+ /**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+ * current user.
+ * <p>
+ * Although this API can be used without any restriction, each session owners can accept or
+ * reject your uses of {@link MediaSession2}.
+ *
+ * @return A list of {@link Session2Token}.
+ */
+ @NonNull
+ public List<Session2Token> getSession2Tokens() {
+ return getSession2Tokens(UserHandle.myUserId());
+ }
+
+ /**
+ * Adds a callback to be notified when the list of active sessions changes.
+ * <p>
+ * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+ * held by the calling app.
+ * </p>
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(MEDIA_CONTENT_CONTROL)
+ public void registerSessionCallback(@CallbackExecutor @NonNull Executor executor,
+ @NonNull SessionCallback callback) {
+ Objects.requireNonNull(executor, "executor must not be null");
+ Objects.requireNonNull(callback, "callback must not be null");
+
+ if (!mTokenCallbackRecords.addIfAbsent(
+ new SessionCallbackRecord(executor, callback))) {
+ Log.w(TAG, "registerSession2TokenCallback: Ignoring the same callback");
+ return;
+ }
+ synchronized (mLock) {
+ if (mCallbackStub == null) {
+ MediaCommunicationServiceCallbackStub callbackStub =
+ new MediaCommunicationServiceCallbackStub();
+ try {
+ mService.registerCallback(callbackStub, mContext.getPackageName());
+ mCallbackStub = callbackStub;
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to register callback.", ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Stops receiving active sessions updates on the specified callback.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void unregisterSessionCallback(@NonNull SessionCallback callback) {
+ if (!mTokenCallbackRecords.remove(
+ new SessionCallbackRecord(null, callback))) {
+ Log.w(TAG, "unregisterSession2TokenCallback: Ignoring an unknown callback.");
+ return;
+ }
+ synchronized (mLock) {
+ if (mCallbackStub != null && mTokenCallbackRecords.isEmpty()) {
+ try {
+ mService.unregisterCallback(mCallbackStub);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to unregister callback.", ex);
+ }
+ mCallbackStub = null;
+ }
+ }
+ }
+
+ private List<Session2Token> getSession2Tokens(int userId) {
+ try {
+ MediaParceledListSlice slice = mService.getSession2Tokens(userId);
+ return slice == null ? Collections.emptyList() : slice.getList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get session tokens", e);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Callback for listening to changes to the sessions.
+ * @see #registerSessionCallback(Executor, SessionCallback)
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public interface SessionCallback {
+ /**
+ * Called when a new {@link MediaSession2 media session2} is created.
+ * @param token the newly created token
+ */
+ default void onSession2TokenCreated(@NonNull Session2Token token) {}
+
+ /**
+ * Called when {@link #getSession2Tokens() session tokens} are changed.
+ */
+ default void onSession2TokensChanged(@NonNull List<Session2Token> tokens) {}
+ }
+
+ private static final class SessionCallbackRecord {
+ public final Executor executor;
+ public final SessionCallback callback;
+
+ SessionCallbackRecord(Executor executor, SessionCallback callback) {
+ this.executor = executor;
+ this.callback = callback;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(callback);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof SessionCallbackRecord)) {
+ return false;
+ }
+ return Objects.equals(this.callback, ((SessionCallbackRecord) obj).callback);
+ }
+ }
+
+ class MediaCommunicationServiceCallbackStub extends IMediaCommunicationServiceCallback.Stub {
+ @Override
+ public void onSession2Created(Session2Token token) throws RemoteException {
+ for (SessionCallbackRecord record : mTokenCallbackRecords) {
+ record.executor.execute(() -> record.callback.onSession2TokenCreated(token));
+ }
+ }
+
+ @Override
+ public void onSession2Changed(MediaParceledListSlice tokens) throws RemoteException {
+ List<Session2Token> tokenList = tokens.getList();
+ for (SessionCallbackRecord record : mTokenCallbackRecords) {
+ record.executor.execute(() -> record.callback.onSession2TokensChanged(tokenList));
+ }
+ }
+ }
}
diff --git a/apex/media/framework/java/android/media/MediaSession2.java b/apex/media/framework/java/android/media/MediaSession2.java
index 6560afe..6397ba3 100644
--- a/apex/media/framework/java/android/media/MediaSession2.java
+++ b/apex/media/framework/java/android/media/MediaSession2.java
@@ -32,7 +32,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.RemoteUserInfo;
import android.os.BadParcelableException;
import android.os.Bundle;
@@ -87,7 +86,7 @@
private final String mSessionId;
private final PendingIntent mSessionActivity;
private final Session2Token mSessionToken;
- private final MediaSessionManager mSessionManager;
+ private final MediaCommunicationManager mCommunicationManager;
private final Handler mResultHandler;
//@GuardedBy("mLock")
@@ -115,8 +114,7 @@
mSessionStub = new Session2Link(this);
mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
mSessionStub, tokenExtras);
- mSessionManager = (MediaSessionManager) mContext.getSystemService(
- Context.MEDIA_SESSION_SERVICE);
+ mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
// NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
mResultHandler = new Handler(context.getMainLooper());
mClosed = false;
@@ -352,7 +350,7 @@
final ControllerInfo controllerInfo = new ControllerInfo(
remoteUserInfo,
- mSessionManager.isTrustedForMediaControl(remoteUserInfo),
+ mCommunicationManager.isTrustedForMediaControl(remoteUserInfo),
controller,
connectionHints);
mCallbackExecutor.execute(() -> {
@@ -608,8 +606,8 @@
// Notify framework about the newly create session after the constructor is finished.
// Otherwise, framework may access the session before the initialization is finished.
try {
- MediaSessionManager manager = (MediaSessionManager) mContext.getSystemService(
- Context.MEDIA_SESSION_SERVICE);
+ MediaCommunicationManager manager =
+ mContext.getSystemService(MediaCommunicationManager.class);
manager.notifySession2Created(session2.getToken());
} catch (Exception e) {
session2.close();
diff --git a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
index 0468fdf..06de3f8 100644
--- a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
+++ b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
@@ -15,27 +15,538 @@
*/
package com.android.server.media;
-import android.content.Context;
-import android.media.IMediaCommunicationService;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.os.UserHandle.ALL;
+import static android.os.UserHandle.getUserHandleForUid;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.IMediaCommunicationService;
+import android.media.IMediaCommunicationServiceCallback;
+import android.media.MediaController2;
+import android.media.MediaParceledListSlice;
+import android.media.Session2CommandGroup;
+import android.media.Session2Token;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
/**
- * A system service that managers {@link android.media.MediaSession2} creations
+ * A system service that manages {@link android.media.MediaSession2} creations
* and their ongoing media playback state.
* @hide
*/
public class MediaCommunicationService extends SystemService {
+ private static final String TAG = "MediaCommunicationService";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ final Context mContext;
+
+ private final Object mLock = new Object();
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ @GuardedBy("mLock")
+ private final SparseIntArray mFullUserIds = new SparseIntArray();
+ @GuardedBy("mLock")
+ private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<>();
+
+ private final Executor mRecordExecutor = Executors.newSingleThreadExecutor();
+ @GuardedBy("mLock")
+ private final List<CallbackRecord> mCallbackRecords = new ArrayList<>();
+ final NotificationManager mNotificationManager;
public MediaCommunicationService(Context context) {
super(context);
+ mContext = context;
+ mNotificationManager = context.getSystemService(NotificationManager.class);
}
@Override
public void onStart() {
publishBinderService(Context.MEDIA_COMMUNICATION_SERVICE, new Stub());
+ updateUser();
+ }
+
+ @Override
+ public void onUserStarting(@NonNull TargetUser user) {
+ if (DEBUG) Log.d(TAG, "onUserStarting: " + user);
+ updateUser();
+ }
+
+ @Override
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ if (DEBUG) Log.d(TAG, "onUserSwitching: " + to);
+ updateUser();
+ }
+
+ @Override
+ public void onUserStopped(@NonNull TargetUser targetUser) {
+ int userId = targetUser.getUserHandle().getIdentifier();
+
+ if (DEBUG) Log.d(TAG, "onUserStopped: " + userId);
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user != null) {
+ if (user.getFullUserId() == userId) {
+ user.destroySessionsForUserLocked(UserHandle.ALL.getIdentifier());
+ mUserRecords.remove(userId);
+ } else {
+ user.destroySessionsForUserLocked(userId);
+ }
+ }
+ updateUser();
+ }
+ }
+
+ @Nullable
+ CallbackRecord findCallbackRecordLocked(@Nullable IMediaCommunicationServiceCallback callback) {
+ if (callback == null) {
+ return null;
+ }
+ for (CallbackRecord record : mCallbackRecords) {
+ if (Objects.equals(callback.asBinder(), record.mCallback.asBinder())) {
+ return record;
+ }
+ }
+ return null;
+ }
+
+ private FullUserRecord getFullUserRecordLocked(int userId) {
+ int fullUserId = mFullUserIds.get(userId, -1);
+ if (fullUserId < 0) {
+ return null;
+ }
+ return mUserRecords.get(fullUserId);
+ }
+
+ private boolean hasMediaControlPermission(int pid, int uid) {
+ // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+ // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+ // check here.
+ if (uid == Process.SYSTEM_UID || mContext.checkPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else if (DEBUG) {
+ Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+ }
+ return false;
+ }
+
+ private void updateUser() {
+ UserManager manager = mContext.getSystemService(UserManager.class);
+ List<UserHandle> allUsers = manager.getUserHandles(/*excludeDying=*/false);
+
+ synchronized (mLock) {
+ mFullUserIds.clear();
+ if (allUsers != null) {
+ for (UserHandle user : allUsers) {
+ UserHandle parent = manager.getProfileParent(user);
+ if (parent != null) {
+ mFullUserIds.put(user.getIdentifier(), parent.getIdentifier());
+ } else {
+ mFullUserIds.put(user.getIdentifier(), user.getIdentifier());
+ if (mUserRecords.get(user.getIdentifier()) == null) {
+ mUserRecords.put(user.getIdentifier(),
+ new FullUserRecord(user.getIdentifier()));
+ }
+ }
+ }
+ }
+ // Ensure that the current full user exists.
+ int currentFullUserId = ActivityManager.getCurrentUser();
+ FullUserRecord currentFullUserRecord = mUserRecords.get(currentFullUserId);
+ if (currentFullUserRecord == null) {
+ Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
+ currentFullUserRecord = new FullUserRecord(currentFullUserId);
+ mUserRecords.put(currentFullUserId, currentFullUserRecord);
+ }
+ mFullUserIds.put(currentFullUserId, currentFullUserId);
+ }
+ }
+
+ void dispatchSessionCreated(Session2Token token) {
+ for (CallbackRecord record : mCallbackRecords) {
+ if (record.mUserId != ALL.getIdentifier()
+ && record.mUserId != getUserHandleForUid(token.getUid()).getIdentifier()) {
+ continue;
+ }
+ try {
+ record.mCallback.onSession2Created(token);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ void onSessionDied(Session2Record record) {
+ synchronized (mLock) {
+ destroySessionLocked(record);
+ }
+ }
+
+ private void destroySessionLocked(Session2Record session) {
+ if (DEBUG) {
+ Log.d(TAG, "Destroying " + session);
+ }
+ if (session.isClosed()) {
+ Log.w(TAG, "Destroying already destroyed session. Ignoring.");
+ return;
+ }
+
+ FullUserRecord user = getFullUserRecordLocked(session.getUserId());
+
+ if (user != null) {
+ user.removeSession(session);
+ }
+
+ session.close();
}
private class Stub extends IMediaCommunicationService.Stub {
+ @Override
+ public void notifySession2Created(Session2Token sessionToken) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "Session2 is created " + sessionToken);
+ }
+ if (uid != sessionToken.getUid()) {
+ throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
+ + " but actually=" + sessionToken.getUid());
+ }
+ synchronized (mLock) {
+ int userId = getUserHandleForUid(sessionToken.getUid()).getIdentifier();
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null) {
+ Log.w(TAG, "notifySession2Created: Ignore session of an unknown user");
+ return;
+ }
+ user.addSession(new Session2Record(MediaCommunicationService.this,
+ sessionToken, mRecordExecutor));
+ mHandler.post(() -> dispatchSessionCreated(sessionToken));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
+ * permission or an enabled notification listener)
+ *
+ * @param controllerPackageName package name of the controller app
+ * @param controllerPid pid of the controller app
+ * @param controllerUid uid of the controller app
+ */
+ @Override
+ public boolean isTrusted(String controllerPackageName, int controllerPid,
+ int controllerUid) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Don't perform check between controllerPackageName and controllerUid.
+ // When an (activity|service) runs on the another apps process by specifying
+ // android:process in the AndroidManifest.xml, then PID and UID would have the
+ // running process' information instead of the (activity|service) that has created
+ // MediaController.
+ // Note that we can use Context#getOpPackageName() instead of
+ // Context#getPackageName() for getting package name that matches with the PID/UID,
+ // but it doesn't tell which package has created the MediaController, so useless.
+ return hasMediaControlPermission(controllerPid, controllerUid)
+ || hasEnabledNotificationListener(
+ userId, controllerPackageName, controllerUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public MediaParceledListSlice getSession2Tokens(int userId) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ // Check that they can make calls on behalf of the user and get the final user id
+ int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
+ List<Session2Token> result;
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ result = user.getSession2Tokens(resolvedUserId);
+ }
+ return new MediaParceledListSlice(result);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void registerCallback(IMediaCommunicationServiceCallback callback,
+ String packageName) throws RemoteException {
+ Objects.requireNonNull(callback, "callback should not be null");
+ Objects.requireNonNull(packageName, "packageName should not be null");
+
+ synchronized (mLock) {
+ if (findCallbackRecordLocked(callback) == null) {
+
+ CallbackRecord record = new CallbackRecord(callback, packageName,
+ Binder.getCallingUid(), Binder.getCallingPid());
+ mCallbackRecords.add(record);
+ try {
+ callback.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to register callback", e);
+ mCallbackRecords.remove(record);
+ }
+ } else {
+ Log.e(TAG, "registerCallback is called with already registered callback. "
+ + "packageName=" + packageName);
+ }
+ }
+ }
+
+ @Override
+ public void unregisterCallback(IMediaCommunicationServiceCallback callback)
+ throws RemoteException {
+ synchronized (mLock) {
+ CallbackRecord existingRecord = findCallbackRecordLocked(callback);
+ if (existingRecord != null) {
+ mCallbackRecords.remove(existingRecord);
+ callback.asBinder().unlinkToDeath(existingRecord, 0);
+ } else {
+ Log.e(TAG, "unregisterCallback is called with unregistered callback.");
+ }
+ }
+ }
+
+ private boolean hasEnabledNotificationListener(int callingUserId,
+ String controllerPackageName, int controllerUid) {
+ int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier();
+ if (callingUserId != controllerUserId) {
+ // Enabled notification listener only works within the same user.
+ return false;
+ }
+
+ if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName,
+ UserHandle.getUserHandleForUid(controllerUid))) {
+ return true;
+ }
+ if (DEBUG) {
+ Log.d(TAG, controllerPackageName + " (uid=" + controllerUid
+ + ") doesn't have an enabled notification listener");
+ }
+ return false;
+ }
+
+ // Handles incoming user by checking whether the caller has permission to access the
+ // given user id's information or not. Permission is not necessary if the given user id is
+ // equal to the caller's user id, but if not, the caller needs to have the
+ // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown.
+ // The return value will be the given user id, unless the given user id is
+ // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead.
+ private int handleIncomingUser(int pid, int uid, int userId, String packageName) {
+ int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+ if (userId == callingUserId) {
+ return userId;
+ }
+
+ boolean canInteractAcrossUsersFull = mContext.checkPermission(
+ INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED;
+ if (canInteractAcrossUsersFull) {
+ if (userId == UserHandle.CURRENT.getIdentifier()) {
+ return ActivityManager.getCurrentUser();
+ }
+ return userId;
+ }
+
+ throw new SecurityException("Permission denied while calling from " + packageName
+ + " with user id: " + userId + "; Need to run as either the calling user id ("
+ + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission");
+ }
+ }
+
+ final class CallbackRecord implements IBinder.DeathRecipient {
+ private final IMediaCommunicationServiceCallback mCallback;
+ private final String mPackageName;
+ private final int mUid;
+ private int mPid;
+ private final int mUserId;
+
+ CallbackRecord(IMediaCommunicationServiceCallback callback,
+ String packageName, int uid, int pid) {
+ mCallback = callback;
+ mPackageName = packageName;
+ mUid = uid;
+ mPid = pid;
+ mUserId = (mContext.checkPermission(
+ INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED)
+ ? ALL.getIdentifier() : UserHandle.getUserHandleForUid(mUid).getIdentifier();
+ }
+
+ @Override
+ public String toString() {
+ return "CallbackRecord[callback=" + mCallback + ", pkg=" + mPackageName
+ + ", uid=" + mUid + ", pid=" + mPid + "]";
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mCallbackRecords.remove(this);
+ }
+ }
+ }
+
+ final class FullUserRecord {
+ private final int mFullUserId;
+ /** Sorted list of media sessions */
+ private final List<Session2Record> mSessionRecords = new ArrayList<>();
+
+ FullUserRecord(int fullUserId) {
+ mFullUserId = fullUserId;
+ }
+
+ public void addSession(Session2Record record) {
+ mSessionRecords.add(record);
+ }
+
+ public void removeSession(Session2Record record) {
+ mSessionRecords.remove(record);
+ //TODO: Handle if the removed session was the media button session.
+ }
+
+ public int getFullUserId() {
+ return mFullUserId;
+ }
+
+ public List<Session2Token> getSession2Tokens(int userId) {
+ return mSessionRecords.stream()
+ .filter(record -> record.isActive()
+ && (userId == UserHandle.ALL.getIdentifier()
+ || record.getUserId() == userId))
+ .map(Session2Record::getSessionToken)
+ .collect(Collectors.toList());
+ }
+
+ public void destroySessionsForUserLocked(int userId) {
+ synchronized (mLock) {
+ for (Session2Record record : mSessionRecords) {
+ if (userId == UserHandle.ALL.getIdentifier()
+ || record.getUserId() == userId) {
+ destroySessionLocked(record);
+ }
+ }
+ }
+ }
+ }
+
+ static final class Session2Record {
+ private final Session2Token mSessionToken;
+ private final Object mLock = new Object();
+ private final WeakReference<MediaCommunicationService> mServiceRef;
+ @GuardedBy("mLock")
+ private final MediaController2 mController;
+
+ @GuardedBy("mLock")
+ private boolean mIsConnected;
+ @GuardedBy("mLock")
+ private boolean mIsClosed;
+
+ Session2Record(MediaCommunicationService service, Session2Token token,
+ Executor controllerExecutor) {
+ mServiceRef = new WeakReference<>(service);
+ mSessionToken = token;
+ mController = new MediaController2.Builder(service.getContext(), token)
+ .setControllerCallback(controllerExecutor, new Controller2Callback())
+ .build();
+ }
+
+ public int getUserId() {
+ return UserHandle.getUserHandleForUid(mSessionToken.getUid()).getIdentifier();
+ }
+
+ public boolean isActive() {
+ synchronized (mLock) {
+ return mIsConnected;
+ }
+ }
+
+ public boolean isClosed() {
+ synchronized (mLock) {
+ return mIsClosed;
+ }
+ }
+
+ public void close() {
+ synchronized (mLock) {
+ mIsClosed = true;
+ // Call close regardless of the mIsConnected. This may be called when it's not yet
+ // connected.
+ mController.close();
+ }
+ }
+
+ public Session2Token getSessionToken() {
+ return mSessionToken;
+ }
+
+ private class Controller2Callback extends MediaController2.ControllerCallback {
+ @Override
+ public void onConnected(MediaController2 controller,
+ Session2CommandGroup allowedCommands) {
+ if (DEBUG) {
+ Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands);
+ }
+ synchronized (mLock) {
+ mIsConnected = true;
+ }
+ MediaCommunicationService service = mServiceRef.get();
+ if (service != null) {
+ //TODO: notify session state changed
+ }
+ }
+
+ @Override
+ public void onDisconnected(MediaController2 controller) {
+ if (DEBUG) {
+ Log.d(TAG, "disconnected from " + mSessionToken);
+ }
+ synchronized (mLock) {
+ mIsConnected = false;
+ }
+ MediaCommunicationService service = mServiceRef.get();
+ if (service != null) {
+ service.onSessionDied(Session2Record.this);
+ }
+ }
+ }
}
}
diff --git a/api/Android.bp b/api/Android.bp
index 15c1dfc..1d4698e 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -40,6 +40,7 @@
":art.module.public.api{.public.api.txt}",
":conscrypt.module.public.api{.public.api.txt}",
":framework-appsearch{.public.api.txt}",
+ ":framework-connectivity{.public.api.txt}",
":framework-graphics{.public.api.txt}",
":framework-media{.public.api.txt}",
":framework-mediaprovider{.public.api.txt}",
@@ -95,6 +96,7 @@
":art.module.public.api{.public.stubs.source}",
":conscrypt.module.public.api{.public.stubs.source}",
":framework-appsearch{.public.stubs.source}",
+ ":framework-connectivity{.public.stubs.source}",
":framework-graphics{.public.stubs.source}",
":framework-media{.public.stubs.source}",
":framework-mediaprovider{.public.stubs.source}",
@@ -120,6 +122,7 @@
":art.module.public.api{.public.removed-api.txt}",
":conscrypt.module.public.api{.public.removed-api.txt}",
":framework-appsearch{.public.removed-api.txt}",
+ ":framework-connectivity{.public.removed-api.txt}",
":framework-graphics{.public.removed-api.txt}",
":framework-media{.public.removed-api.txt}",
":framework-mediaprovider{.public.removed-api.txt}",
@@ -155,6 +158,7 @@
srcs: [
":android.net.ipsec.ike{.system.api.txt}",
":framework-appsearch{.system.api.txt}",
+ ":framework-connectivity{.system.api.txt}",
":framework-graphics{.system.api.txt}",
":framework-media{.system.api.txt}",
":framework-mediaprovider{.system.api.txt}",
@@ -208,6 +212,7 @@
srcs: [
":android.net.ipsec.ike{.system.removed-api.txt}",
":framework-appsearch{.system.removed-api.txt}",
+ ":framework-connectivity{.system.removed-api.txt}",
":framework-graphics{.system.removed-api.txt}",
":framework-media{.system.removed-api.txt}",
":framework-mediaprovider{.system.removed-api.txt}",
@@ -243,6 +248,7 @@
srcs: [
":android.net.ipsec.ike{.module-lib.api.txt}",
":framework-appsearch{.module-lib.api.txt}",
+ ":framework-connectivity{.module-lib.api.txt}",
":framework-graphics{.module-lib.api.txt}",
":framework-media{.module-lib.api.txt}",
":framework-mediaprovider{.module-lib.api.txt}",
@@ -298,6 +304,7 @@
srcs: [
":android.net.ipsec.ike{.module-lib.removed-api.txt}",
":framework-appsearch{.module-lib.removed-api.txt}",
+ ":framework-connectivity{.module-lib.removed-api.txt}",
":framework-graphics{.module-lib.removed-api.txt}",
":framework-media{.module-lib.removed-api.txt}",
":framework-mediaprovider{.module-lib.removed-api.txt}",
diff --git a/config/dirty-image-objects b/config/dirty-image-objects
index 2dfe019..dfd091c 100644
--- a/config/dirty-image-objects
+++ b/config/dirty-image-objects
@@ -28,359 +28,359 @@
# Then, grep for lines containing "Private dirty object" from the output.
# This particular file was generated by dumping systemserver and systemui.
#
-android.accounts.Account
-android.accounts.OnAccountsUpdateListener
-android.animation.LayoutTransition
-android.app.ActivityManager
-android.app.ActivityManager$OnUidImportanceListener
-android.app.ActivityTaskManager
-android.app.ActivityThread
-android.app.admin.DevicePolicyManager
-android.app.AlarmManager
-android.app.Application
-android.app.AppOpsManager
-android.app.backup.BackupManager
-android.app.ContextImpl
-android.app.INotificationManager
-android.app.Notification$BigPictureStyle
-android.app.Notification$BigTextStyle
-android.app.Notification$InboxStyle
-android.app.NotificationChannel
-android.app.NotificationChannelGroup
-android.app.NotificationManager
-android.app.PendingIntent
-android.app.PendingIntent$OnFinished
-android.app.QueuedWork
-android.app.ResourcesManager
-android.app.WallpaperManager
-android.app.WindowConfiguration
-android.bluetooth.BluetoothAdapter
-android.bluetooth.BluetoothDevice
-android.bluetooth.BluetoothProfile
-android.bluetooth.IBluetoothA2dp
-android.bluetooth.IBluetoothHeadsetPhone
-android.bluetooth.IBluetoothHidDevice
-android.bluetooth.IBluetoothHidHost
-android.bluetooth.IBluetoothMap
-android.bluetooth.IBluetoothPan
-android.bluetooth.IBluetoothPbap
-android.bluetooth.IBluetoothSap
-android.content.ClipboardManager$OnPrimaryClipChangedListener
-android.content.ComponentName
-android.content.ContentProvider$PipeDataWriter
-android.content.ContentResolver
-android.content.Context
-android.content.Intent
-android.content.pm.PackageManager$OnPermissionsChangedListener
-android.content.pm.VersionedPackage
-android.content.res.Configuration
-android.content.SharedPreferences$OnSharedPreferenceChangeListener
-android.database.CursorWindow
-android.database.sqlite.SQLiteCompatibilityWalFlags
-android.database.sqlite.SQLiteDatabase$CursorFactory
-android.database.sqlite.SQLiteGlobal
-android.database.sqlite.SQLiteTransactionListener
-android.ddm.DdmHandleAppName
-android.graphics.Bitmap
-android.graphics.Canvas
-android.graphics.drawable.AdaptiveIconDrawable
-android.graphics.drawable.ColorDrawable
-android.graphics.drawable.GradientDrawable
-android.graphics.drawable.Icon
-android.graphics.drawable.InsetDrawable
-android.graphics.drawable.RippleDrawable
-android.graphics.drawable.VectorDrawable$VGroup
-android.graphics.ImageDecoder
-android.graphics.Rect
-android.graphics.TemporaryBuffer
-android.hardware.biometrics.BiometricSourceType
-android.hardware.display.ColorDisplayManager$ColorDisplayManagerInternal
-android.hardware.display.DisplayManagerGlobal
-android.hardware.display.NightDisplayListener$Callback
-android.hardware.input.InputManager
-android.hardware.input.InputManager$InputDeviceListener
-android.hardware.SensorPrivacyManager
-android.hardware.SystemSensorManager
-android.icu.impl.OlsonTimeZone
-android.icu.text.BreakIterator
-android.icu.text.Collator
-android.icu.text.DateFormat$BooleanAttribute
-android.icu.text.DateTimePatternGenerator$DTPGflags
-android.icu.text.PluralRules$Operand
-android.icu.util.TimeZone
-android.location.GpsStatus$Listener
-android.location.LocationListener
-android.media.AudioManager
-android.media.MediaRouter
-android.media.PlayerBase
-android.media.session.MediaSessionManager
-android.net.apf.ApfCapabilities
-android.net.ConnectivityManager
-android.net.ConnectivityManager$OnNetworkActiveListener
-android.net.ConnectivityThread$Singleton
-android.net.IpConfiguration$IpAssignment
-android.net.IpConfiguration$ProxySettings
-android.net.IpPrefix
-android.net.LinkAddress
-android.net.LinkProperties
-android.net.Network
-android.net.NetworkCapabilities
-android.net.NetworkInfo
-android.net.NetworkInfo$State
-android.net.NetworkRequest
-android.net.NetworkRequest$Type
-android.net.RouteInfo
-android.net.StringNetworkSpecifier
-android.net.TrafficStats
-android.net.UidRange
-android.net.Uri$HierarchicalUri
-android.net.Uri$StringUri
-android.net.wifi.WifiManager
-android.net.wifi.WifiManager$SoftApCallback
-android.os.AsyncResult
-android.os.AsyncTask
-android.os.BinderProxy
-android.os.Bundle
-android.os.DeadObjectException
-android.os.Environment
-android.os.FileObserver
-android.os.Handler
-android.os.IDeviceIdleController
-android.os.LocaleList
-android.os.Looper
-android.os.Message
-android.os.ParcelUuid
-android.os.Process
-android.os.RecoverySystem
-android.os.ServiceManager
-android.os.storage.StorageManager
-android.os.StrictMode
-android.os.Trace
-android.os.WorkSource
-android.os.WorkSource$WorkChain
-android.permission.PermissionManager
-android.provider.FontsContract
-android.provider.Settings$SettingNotFoundException
-android.renderscript.RenderScriptCacheDir
-android.security.IKeyChainService
-android.security.keystore.AndroidKeyStoreProvider
-android.security.net.config.ApplicationConfig
-android.security.net.config.SystemCertificateSource$NoPreloadHolder
-android.telecom.PhoneAccountHandle
-android.telephony.AnomalyReporter
-android.telephony.CellSignalStrengthCdma
-android.telephony.CellSignalStrengthGsm
-android.telephony.CellSignalStrengthLte
-android.telephony.CellSignalStrengthNr
-android.telephony.CellSignalStrengthTdscdma
-android.telephony.CellSignalStrengthWcdma
-android.telephony.DataSpecificRegistrationInfo
-android.telephony.emergency.EmergencyNumber
-android.telephony.ims.ImsMmTelManager$CapabilityCallback$CapabilityBinder
-android.telephony.ims.ImsMmTelManager$RegistrationCallback$RegistrationBinder
-android.telephony.ims.ImsReasonInfo
-android.telephony.ims.ProvisioningManager$Callback$CallbackBinder
-android.telephony.ModemActivityInfo
-android.telephony.ModemInfo
-android.telephony.NetworkRegistrationInfo
-android.telephony.NetworkService
-android.telephony.TelephonyManager
-android.telephony.VoiceSpecificRegistrationInfo
-android.text.format.DateFormat
-android.text.method.SingleLineTransformationMethod
-android.text.Selection$MemoryTextWatcher
-android.text.SpanWatcher
-android.text.style.AlignmentSpan
-android.text.style.CharacterStyle
-android.text.style.LeadingMarginSpan
-android.text.style.LineBackgroundSpan
-android.text.style.LineHeightSpan
-android.text.style.MetricAffectingSpan
-android.text.style.ReplacementSpan
-android.text.style.SuggestionSpan
-android.text.style.TabStopSpan
-android.text.TextUtils
-android.text.TextWatcher
-android.transition.ChangeClipBounds
-android.transition.ChangeImageTransform
-android.transition.ChangeTransform
-android.util.ArrayMap
-android.util.ArraySet
-android.util.DisplayMetrics
-android.util.EventLog
-android.util.Log
-android.util.Patterns
-android.view.AbsSavedState$1
-android.view.accessibility.AccessibilityManager
-android.view.accessibility.AccessibilityManager$AccessibilityServicesStateChangeListener
-android.view.accessibility.AccessibilityManager$TouchExplorationStateChangeListener
-android.view.accessibility.AccessibilityNodeIdManager
-android.view.autofill.AutofillManager
-android.view.autofill.Helper
-android.view.Choreographer
-android.view.inputmethod.InputMethodManager
-android.view.IWindowManager
-android.view.PointerIcon
-android.view.RemoteAnimationAdapter
-android.view.ThreadedRenderer
-android.view.View
-android.view.View$OnHoverListener
-android.view.ViewRootImpl
-android.view.ViewStub
-android.view.ViewStub$OnInflateListener
-android.view.ViewTreeObserver
-android.view.WindowManager$LayoutParams
-android.view.WindowManagerGlobal
-android.widget.ActionMenuPresenter$OverflowMenuButton
-android.widget.ActionMenuView
-android.widget.Button
-android.widget.CheckBox
-android.widget.FrameLayout
-android.widget.ImageButton
-android.widget.ImageView
-android.widget.LinearLayout
-android.widget.RelativeLayout
-android.widget.SeekBar
-android.widget.Space
-android.widget.TextView
-android.widget.Toolbar
-byte[]
-com.android.ims.ImsManager
-com.android.internal.logging.MetricsLogger
-com.android.internal.os.BackgroundThread
-com.android.internal.os.BinderInternal
-com.android.internal.os.BinderInternal$BinderProxyLimitListener
-com.android.internal.os.RuntimeInit
-com.android.internal.os.SomeArgs
-com.android.internal.policy.DecorView
-com.android.internal.statusbar.IStatusBarService
-com.android.internal.telephony.AppSmsManager
-android.telephony.CallerInfoAsyncQuery$OnQueryCompleteListener
-com.android.internal.telephony.CarrierActionAgent
-com.android.internal.telephony.cat.CatService
-com.android.internal.telephony.cat.IconLoader
-com.android.internal.telephony.cat.RilMessageDecoder
-com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager
-com.android.internal.telephony.cdma.EriManager
-com.android.internal.telephony.CellularNetworkValidator
-com.android.internal.telephony.CommandException
-com.android.internal.telephony.dataconnection.DataConnection$DcActivatingState
-com.android.internal.telephony.dataconnection.DataConnection$DcActiveState
-com.android.internal.telephony.dataconnection.DataConnection$DcInactiveState
-com.android.internal.telephony.dataconnection.DataEnabledSettings
-com.android.internal.telephony.dataconnection.DcTracker
-com.android.internal.telephony.euicc.EuiccCardController
-com.android.internal.telephony.euicc.EuiccController
-com.android.internal.telephony.GsmAlphabet
-com.android.internal.telephony.GsmCdmaCallTracker
-com.android.internal.telephony.GsmCdmaPhone
-com.android.internal.telephony.IccPhoneBookInterfaceManager
-com.android.internal.telephony.IccSmsInterfaceManager
-com.android.internal.telephony.ims.ImsResolver
-com.android.internal.telephony.imsphone.ImsExternalCallTracker
-com.android.internal.telephony.imsphone.ImsPhone
-com.android.internal.telephony.imsphone.ImsPhoneCallTracker
-com.android.internal.telephony.ims.RcsMessageStoreController
-com.android.internal.telephony.IntentBroadcaster
-com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy
-com.android.internal.telephony.metrics.TelephonyMetrics
-com.android.internal.telephony.MultiSimSettingController
-com.android.internal.telephony.nano.CarrierIdProto$CarrierAttribute
-com.android.internal.telephony.nano.CarrierIdProto$CarrierId
-com.android.internal.telephony.nano.TelephonyProto$RilDataCall
-com.android.internal.telephony.nano.TelephonyProto$SmsSession$Event
-com.android.internal.telephony.nano.TelephonyProto$TelephonyCallSession$Event$RilCall
-com.android.internal.telephony.NitzStateMachine
-com.android.internal.telephony.PhoneConfigurationManager
-com.android.internal.telephony.PhoneFactory
-com.android.internal.telephony.PhoneSwitcher
-com.android.internal.telephony.ProxyController
-com.android.internal.telephony.RadioConfig
-com.android.internal.telephony.RIL
-com.android.internal.telephony.RILRequest
-com.android.internal.telephony.RilWakelockInfo
-com.android.internal.telephony.ServiceStateTracker
-com.android.internal.telephony.SimActivationTracker
-com.android.internal.telephony.SmsApplication
-com.android.internal.telephony.SmsBroadcastUndelivered
-com.android.internal.telephony.SmsStorageMonitor
-com.android.internal.telephony.SmsUsageMonitor
-com.android.internal.telephony.SubscriptionController
-com.android.internal.telephony.SubscriptionInfoUpdater
-com.android.internal.telephony.TelephonyComponentFactory
-com.android.internal.telephony.TelephonyDevController
-com.android.internal.telephony.TelephonyTester
-com.android.internal.telephony.uicc.AdnRecordCache
-com.android.internal.telephony.uicc.UiccCardApplication
-com.android.internal.telephony.uicc.UiccController
-com.android.internal.telephony.uicc.UiccProfile
-com.android.internal.telephony.uicc.UiccStateChangedLauncher
-com.android.internal.telephony.uicc.UsimFileHandler
-com.android.internal.telephony.uicc.VoiceMailConstants
-com.android.internal.util.LatencyTracker
-com.android.internal.util.StateMachine$SmHandler
-com.android.okhttp.OkHttpClient
-com.android.okhttp.okio.AsyncTimeout
-com.android.okhttp.okio.SegmentPool
-com.android.phone.ecc.nano.ProtobufEccData$CountryInfo
-com.android.phone.ecc.nano.ProtobufEccData$EccInfo
-com.android.server.sip.SipWakeupTimer
-com.android.server.SystemConfig
-dalvik.system.BaseDexClassLoader
-dalvik.system.BlockGuard
-dalvik.system.CloseGuard
-dalvik.system.RuntimeHooks
-dalvik.system.SocketTagger
-java.io.BufferedReader
-java.lang.AssertionError
-java.lang.Boolean
-java.lang.Byte
-java.lang.Character
-java.lang.CharSequence
-java.lang.Class
-java.lang.IllegalAccessException
-java.lang.IllegalStateException
-java.lang.NoSuchMethodException
-java.lang.NullPointerException
-java.lang.Object
-java.lang.Object[]
-java.lang.ref.FinalizerReference
-java.lang.Runnable
-java.lang.SecurityException
-java.lang.Short
-java.lang.String[]
-java.lang.System
-java.lang.Thread
-java.lang.Throwable
-java.lang.UnsatisfiedLinkError
-java.net.Inet6Address
-java.net.Socket
-java.net.SocketException
-java.nio.Bits
-java.nio.charset.Charset
-java.security.interfaces.RSAPrivateKey
-java.security.Provider
-java.util.Collections
-java.util.concurrent.Executor
-java.util.GregorianCalendar
-java.util.Locale
-java.util.Locale$NoImagePreloadHolder
-java.util.Scanner
-java.util.Set
-java.util.TimeZone
-javax.net.SocketFactory
-javax.net.ssl.HttpsURLConnection
-javax.net.ssl.HttpsURLConnection$NoPreloadHolder
-javax.net.ssl.SSLContext
-javax.net.ssl.SSLSessionContext
-javax.net.ssl.SSLSocketFactory
-libcore.io.Libcore
-libcore.io.Memory
-libcore.net.NetworkSecurityPolicy
-libcore.timezone.TimeZoneFinder
-org.apache.http.params.HttpParams
-sun.misc.Cleaner
-sun.nio.ch.FileChannelImpl
-sun.nio.ch.FileChannelImpl$Unmapper
-sun.nio.fs.UnixChannelFactory
-sun.security.jca.Providers
+Landroid/accounts/Account;
+Landroid/accounts/OnAccountsUpdateListener;
+Landroid/animation/LayoutTransition;
+Landroid/app/ActivityManager;
+Landroid/app/ActivityManager$OnUidImportanceListener;
+Landroid/app/ActivityTaskManager;
+Landroid/app/ActivityThread;
+Landroid/app/admin/DevicePolicyManager;
+Landroid/app/AlarmManager;
+Landroid/app/Application;
+Landroid/app/AppOpsManager;
+Landroid/app/backup/BackupManager;
+Landroid/app/ContextImpl;
+Landroid/app/INotificationManager;
+Landroid/app/Notification$BigPictureStyle;
+Landroid/app/Notification$BigTextStyle;
+Landroid/app/Notification$InboxStyle;
+Landroid/app/NotificationChannel;
+Landroid/app/NotificationChannelGroup;
+Landroid/app/NotificationManager;
+Landroid/app/PendingIntent;
+Landroid/app/PendingIntent$OnFinished;
+Landroid/app/QueuedWork;
+Landroid/app/ResourcesManager;
+Landroid/app/WallpaperManager;
+Landroid/app/WindowConfiguration;
+Landroid/bluetooth/BluetoothAdapter;
+Landroid/bluetooth/BluetoothDevice;
+Landroid/bluetooth/BluetoothProfile;
+Landroid/bluetooth/IBluetoothA2dp;
+Landroid/bluetooth/IBluetoothHeadsetPhone;
+Landroid/bluetooth/IBluetoothHidDevice;
+Landroid/bluetooth/IBluetoothHidHost;
+Landroid/bluetooth/IBluetoothMap;
+Landroid/bluetooth/IBluetoothPan;
+Landroid/bluetooth/IBluetoothPbap;
+Landroid/bluetooth/IBluetoothSap;
+Landroid/content/ClipboardManager$OnPrimaryClipChangedListener;
+Landroid/content/ComponentName;
+Landroid/content/ContentProvider$PipeDataWriter;
+Landroid/content/ContentResolver;
+Landroid/content/Context;
+Landroid/content/Intent;
+Landroid/content/pm/PackageManager$OnPermissionsChangedListener;
+Landroid/content/pm/VersionedPackage;
+Landroid/content/res/Configuration;
+Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;
+Landroid/database/CursorWindow;
+Landroid/database/sqlite/SQLiteCompatibilityWalFlags;
+Landroid/database/sqlite/SQLiteDatabase$CursorFactory;
+Landroid/database/sqlite/SQLiteGlobal;
+Landroid/database/sqlite/SQLiteTransactionListener;
+Landroid/ddm/DdmHandleAppName;
+Landroid/graphics/Bitmap;
+Landroid/graphics/Canvas;
+Landroid/graphics/drawable/AdaptiveIconDrawable;
+Landroid/graphics/drawable/ColorDrawable;
+Landroid/graphics/drawable/GradientDrawable;
+Landroid/graphics/drawable/Icon;
+Landroid/graphics/drawable/InsetDrawable;
+Landroid/graphics/drawable/RippleDrawable;
+Landroid/graphics/drawable/VectorDrawable$VGroup;
+Landroid/graphics/ImageDecoder;
+Landroid/graphics/Rect;
+Landroid/graphics/TemporaryBuffer;
+Landroid/hardware/biometrics/BiometricSourceType;
+Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal;
+Landroid/hardware/display/DisplayManagerGlobal;
+Landroid/hardware/display/NightDisplayListener$Callback;
+Landroid/hardware/input/InputManager;
+Landroid/hardware/input/InputManager$InputDeviceListener;
+Landroid/hardware/SensorPrivacyManager;
+Landroid/hardware/SystemSensorManager;
+Landroid/icu/impl/OlsonTimeZone;
+Landroid/icu/text/BreakIterator;
+Landroid/icu/text/Collator;
+Landroid/icu/text/DateFormat$BooleanAttribute;
+Landroid/icu/text/DateTimePatternGenerator$DTPGflags;
+Landroid/icu/text/PluralRules$Operand;
+Landroid/icu/util/TimeZone;
+Landroid/location/GpsStatus$Listener;
+Landroid/location/LocationListener;
+Landroid/media/AudioManager;
+Landroid/media/MediaRouter;
+Landroid/media/PlayerBase;
+Landroid/media/session/MediaSessionManager;
+Landroid/net/apf/ApfCapabilities;
+Landroid/net/ConnectivityManager;
+Landroid/net/ConnectivityManager$OnNetworkActiveListener;
+Landroid/net/ConnectivityThread$Singleton;
+Landroid/net/IpConfiguration$IpAssignment;
+Landroid/net/IpConfiguration$ProxySettings;
+Landroid/net/IpPrefix;
+Landroid/net/LinkAddress;
+Landroid/net/LinkProperties;
+Landroid/net/Network;
+Landroid/net/NetworkCapabilities;
+Landroid/net/NetworkInfo;
+Landroid/net/NetworkInfo$State;
+Landroid/net/NetworkRequest;
+Landroid/net/NetworkRequest$Type;
+Landroid/net/RouteInfo;
+Landroid/net/StringNetworkSpecifier;
+Landroid/net/TrafficStats;
+Landroid/net/UidRange;
+Landroid/net/Uri$HierarchicalUri;
+Landroid/net/Uri$StringUri;
+Landroid/net/wifi/WifiManager;
+Landroid/net/wifi/WifiManager$SoftApCallback;
+Landroid/os/AsyncResult;
+Landroid/os/AsyncTask;
+Landroid/os/BinderProxy;
+Landroid/os/Bundle;
+Landroid/os/DeadObjectException;
+Landroid/os/Environment;
+Landroid/os/FileObserver;
+Landroid/os/Handler;
+Landroid/os/IDeviceIdleController;
+Landroid/os/LocaleList;
+Landroid/os/Looper;
+Landroid/os/Message;
+Landroid/os/ParcelUuid;
+Landroid/os/Process;
+Landroid/os/RecoverySystem;
+Landroid/os/ServiceManager;
+Landroid/os/storage/StorageManager;
+Landroid/os/StrictMode;
+Landroid/os/Trace;
+Landroid/os/WorkSource;
+Landroid/os/WorkSource$WorkChain;
+Landroid/permission/PermissionManager;
+Landroid/provider/FontsContract;
+Landroid/provider/Settings$SettingNotFoundException;
+Landroid/renderscript/RenderScriptCacheDir;
+Landroid/security/IKeyChainService;
+Landroid/security/keystore/AndroidKeyStoreProvider;
+Landroid/security/net/config/ApplicationConfig;
+Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder;
+Landroid/telecom/PhoneAccountHandle;
+Landroid/telephony/AnomalyReporter;
+Landroid/telephony/CellSignalStrengthCdma;
+Landroid/telephony/CellSignalStrengthGsm;
+Landroid/telephony/CellSignalStrengthLte;
+Landroid/telephony/CellSignalStrengthNr;
+Landroid/telephony/CellSignalStrengthTdscdma;
+Landroid/telephony/CellSignalStrengthWcdma;
+Landroid/telephony/DataSpecificRegistrationInfo;
+Landroid/telephony/emergency/EmergencyNumber;
+Landroid/telephony/ims/ImsMmTelManager$CapabilityCallback$CapabilityBinder;
+Landroid/telephony/ims/ImsMmTelManager$RegistrationCallback$RegistrationBinder;
+Landroid/telephony/ims/ImsReasonInfo;
+Landroid/telephony/ims/ProvisioningManager$Callback$CallbackBinder;
+Landroid/telephony/ModemActivityInfo;
+Landroid/telephony/ModemInfo;
+Landroid/telephony/NetworkRegistrationInfo;
+Landroid/telephony/NetworkService;
+Landroid/telephony/TelephonyManager;
+Landroid/telephony/VoiceSpecificRegistrationInfo;
+Landroid/text/format/DateFormat;
+Landroid/text/method/SingleLineTransformationMethod;
+Landroid/text/Selection$MemoryTextWatcher;
+Landroid/text/SpanWatcher;
+Landroid/text/style/AlignmentSpan;
+Landroid/text/style/CharacterStyle;
+Landroid/text/style/LeadingMarginSpan;
+Landroid/text/style/LineBackgroundSpan;
+Landroid/text/style/LineHeightSpan;
+Landroid/text/style/MetricAffectingSpan;
+Landroid/text/style/ReplacementSpan;
+Landroid/text/style/SuggestionSpan;
+Landroid/text/style/TabStopSpan;
+Landroid/text/TextUtils;
+Landroid/text/TextWatcher;
+Landroid/transition/ChangeClipBounds;
+Landroid/transition/ChangeImageTransform;
+Landroid/transition/ChangeTransform;
+Landroid/util/ArrayMap;
+Landroid/util/ArraySet;
+Landroid/util/DisplayMetrics;
+Landroid/util/EventLog;
+Landroid/util/Log;
+Landroid/util/Patterns;
+Landroid/view/AbsSavedState$1;
+Landroid/view/accessibility/AccessibilityManager;
+Landroid/view/accessibility/AccessibilityManager$AccessibilityServicesStateChangeListener;
+Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener;
+Landroid/view/accessibility/AccessibilityNodeIdManager;
+Landroid/view/autofill/AutofillManager;
+Landroid/view/autofill/Helper;
+Landroid/view/Choreographer;
+Landroid/view/inputmethod/InputMethodManager;
+Landroid/view/IWindowManager;
+Landroid/view/PointerIcon;
+Landroid/view/RemoteAnimationAdapter;
+Landroid/view/ThreadedRenderer;
+Landroid/view/View;
+Landroid/view/View$OnHoverListener;
+Landroid/view/ViewRootImpl;
+Landroid/view/ViewStub;
+Landroid/view/ViewStub$OnInflateListener;
+Landroid/view/ViewTreeObserver;
+Landroid/view/WindowManager$LayoutParams;
+Landroid/view/WindowManagerGlobal;
+Landroid/widget/ActionMenuPresenter$OverflowMenuButton;
+Landroid/widget/ActionMenuView;
+Landroid/widget/Button;
+Landroid/widget/CheckBox;
+Landroid/widget/FrameLayout;
+Landroid/widget/ImageButton;
+Landroid/widget/ImageView;
+Landroid/widget/LinearLayout;
+Landroid/widget/RelativeLayout;
+Landroid/widget/SeekBar;
+Landroid/widget/Space;
+Landroid/widget/TextView;
+Landroid/widget/Toolbar;
+[B
+Lcom/android/ims/ImsManager;
+Lcom/android/internal/logging/MetricsLogger;
+Lcom/android/internal/os/BackgroundThread;
+Lcom/android/internal/os/BinderInternal;
+Lcom/android/internal/os/BinderInternal$BinderProxyLimitListener;
+Lcom/android/internal/os/RuntimeInit;
+Lcom/android/internal/os/SomeArgs;
+Lcom/android/internal/policy/DecorView;
+Lcom/android/internal/statusbar/IStatusBarService;
+Lcom/android/internal/telephony/AppSmsManager;
+Landroid/telephony/CallerInfoAsyncQuery$OnQueryCompleteListener;
+Lcom/android/internal/telephony/CarrierActionAgent;
+Lcom/android/internal/telephony/cat/CatService;
+Lcom/android/internal/telephony/cat/IconLoader;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
+Lcom/android/internal/telephony/cdma/EriManager;
+Lcom/android/internal/telephony/CellularNetworkValidator;
+Lcom/android/internal/telephony/CommandException;
+Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState;
+Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
+Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState;
+Lcom/android/internal/telephony/dataconnection/DataEnabledSettings;
+Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/euicc/EuiccCardController;
+Lcom/android/internal/telephony/euicc/EuiccController;
+Lcom/android/internal/telephony/GsmAlphabet;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/ims/ImsResolver;
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhone;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/ims/RcsMessageStoreController;
+Lcom/android/internal/telephony/IntentBroadcaster;
+Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;
+Lcom/android/internal/telephony/metrics/TelephonyMetrics;
+Lcom/android/internal/telephony/MultiSimSettingController;
+Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierAttribute;
+Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierId;
+Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall;
+Lcom/android/internal/telephony/nano/TelephonyProto$SmsSession$Event;
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall;
+Lcom/android/internal/telephony/NitzStateMachine;
+Lcom/android/internal/telephony/PhoneConfigurationManager;
+Lcom/android/internal/telephony/PhoneFactory;
+Lcom/android/internal/telephony/PhoneSwitcher;
+Lcom/android/internal/telephony/ProxyController;
+Lcom/android/internal/telephony/RadioConfig;
+Lcom/android/internal/telephony/RIL;
+Lcom/android/internal/telephony/RILRequest;
+Lcom/android/internal/telephony/RilWakelockInfo;
+Lcom/android/internal/telephony/ServiceStateTracker;
+Lcom/android/internal/telephony/SimActivationTracker;
+Lcom/android/internal/telephony/SmsApplication;
+Lcom/android/internal/telephony/SmsBroadcastUndelivered;
+Lcom/android/internal/telephony/SmsStorageMonitor;
+Lcom/android/internal/telephony/SmsUsageMonitor;
+Lcom/android/internal/telephony/SubscriptionController;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;
+Lcom/android/internal/telephony/TelephonyComponentFactory;
+Lcom/android/internal/telephony/TelephonyDevController;
+Lcom/android/internal/telephony/TelephonyTester;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/uicc/UiccProfile;
+Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher;
+Lcom/android/internal/telephony/uicc/UsimFileHandler;
+Lcom/android/internal/telephony/uicc/VoiceMailConstants;
+Lcom/android/internal/util/LatencyTracker;
+Lcom/android/internal/util/StateMachine$SmHandler;
+Lcom/android/okhttp/OkHttpClient;
+Lcom/android/okhttp/okio/AsyncTimeout;
+Lcom/android/okhttp/okio/SegmentPool;
+Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo;
+Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo;
+Lcom/android/server/sip/SipWakeupTimer;
+Lcom/android/server/SystemConfig;
+Ldalvik/system/BaseDexClassLoader;
+Ldalvik/system/BlockGuard;
+Ldalvik/system/CloseGuard;
+Ldalvik/system/RuntimeHooks;
+Ldalvik/system/SocketTagger;
+Ljava/io/BufferedReader;
+Ljava/lang/AssertionError;
+Ljava/lang/Boolean;
+Ljava/lang/Byte;
+Ljava/lang/Character;
+Ljava/lang/CharSequence;
+Ljava/lang/Class;
+Ljava/lang/IllegalAccessException;
+Ljava/lang/IllegalStateException;
+Ljava/lang/NoSuchMethodException;
+Ljava/lang/NullPointerException;
+Ljava/lang/Object;
+[Ljava/lang/Object;
+Ljava/lang/ref/FinalizerReference;
+Ljava/lang/Runnable;
+Ljava/lang/SecurityException;
+Ljava/lang/Short;
+[Ljava/lang/String;
+Ljava/lang/System;
+Ljava/lang/Thread;
+Ljava/lang/Throwable;
+Ljava/lang/UnsatisfiedLinkError;
+Ljava/net/Inet6Address;
+Ljava/net/Socket;
+Ljava/net/SocketException;
+Ljava/nio/Bits;
+Ljava/nio/charset/Charset;
+Ljava/security/interfaces/RSAPrivateKey;
+Ljava/security/Provider;
+Ljava/util/Collections;
+Ljava/util/concurrent/Executor;
+Ljava/util/GregorianCalendar;
+Ljava/util/Locale;
+Ljava/util/Locale$NoImagePreloadHolder;
+Ljava/util/Scanner;
+Ljava/util/Set;
+Ljava/util/TimeZone;
+Ljavax/net/SocketFactory;
+Ljavax/net/ssl/HttpsURLConnection;
+Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder;
+Ljavax/net/ssl/SSLContext;
+Ljavax/net/ssl/SSLSessionContext;
+Ljavax/net/ssl/SSLSocketFactory;
+Llibcore/io/Libcore;
+Llibcore/io/Memory;
+Llibcore/net/NetworkSecurityPolicy;
+Llibcore/timezone/TimeZoneFinder;
+Lorg/apache/http/params/HttpParams;
+Lsun/misc/Cleaner;
+Lsun/nio/ch/FileChannelImpl;
+Lsun/nio/ch/FileChannelImpl$Unmapper;
+Lsun/nio/fs/UnixChannelFactory;
+Lsun/security/jca/Providers;
diff --git a/core/api/current.txt b/core/api/current.txt
index 6b27567..709032b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -21,7 +21,6 @@
field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
- field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -134,7 +133,6 @@
field public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
field public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
field public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
- field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
@@ -6270,14 +6268,14 @@
method public static android.app.PendingIntent getActivities(android.content.Context, int, @NonNull android.content.Intent[], int, @Nullable android.os.Bundle);
method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int);
method public static android.app.PendingIntent getActivity(android.content.Context, int, @NonNull android.content.Intent, int, @Nullable android.os.Bundle);
- method public static android.app.PendingIntent getBroadcast(android.content.Context, int, android.content.Intent, int);
- method @Nullable public String getCreatorPackage();
+ method public static android.app.PendingIntent getBroadcast(android.content.Context, int, @NonNull android.content.Intent, int);
+ method @NonNull public String getCreatorPackage();
method public int getCreatorUid();
- method @Nullable public android.os.UserHandle getCreatorUserHandle();
+ method @NonNull public android.os.UserHandle getCreatorUserHandle();
method public static android.app.PendingIntent getForegroundService(android.content.Context, int, @NonNull android.content.Intent, int);
- method public android.content.IntentSender getIntentSender();
+ method @NonNull public android.content.IntentSender getIntentSender();
method public static android.app.PendingIntent getService(android.content.Context, int, @NonNull android.content.Intent, int);
- method @Deprecated public String getTargetPackage();
+ method @Deprecated @NonNull public String getTargetPackage();
method public boolean isActivity();
method public boolean isBroadcast();
method public boolean isForegroundService();
@@ -6812,14 +6810,18 @@
public final class WallpaperColors implements android.os.Parcelable {
ctor public WallpaperColors(android.os.Parcel);
ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color);
+ ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
method public int describeContents();
method public static android.app.WallpaperColors fromBitmap(@NonNull android.graphics.Bitmap);
method public static android.app.WallpaperColors fromDrawable(android.graphics.drawable.Drawable);
+ method public int getColorHints();
method @NonNull public android.graphics.Color getPrimaryColor();
method @Nullable public android.graphics.Color getSecondaryColor();
method @Nullable public android.graphics.Color getTertiaryColor();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
+ field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
+ field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
}
public final class WallpaperInfo implements android.os.Parcelable {
@@ -9741,7 +9743,7 @@
public interface DeviceFilter<D extends android.os.Parcelable> extends android.os.Parcelable {
}
- public class DeviceNotAssociatedException extends java.lang.Exception {
+ public class DeviceNotAssociatedException extends java.lang.RuntimeException {
}
public final class WifiDeviceFilter implements android.companion.DeviceFilter<android.net.wifi.ScanResult> {
@@ -12563,7 +12565,6 @@
field public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
field public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
- field public static final int FLAG_PERMISSION_ALLOWLIST_ROLE = 8; // 0x8
field public static final int FLAG_PERMISSION_WHITELIST_INSTALLER = 2; // 0x2
field public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1; // 0x1
field public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 4; // 0x4
@@ -12702,7 +12703,6 @@
field public static final int FLAG_HARD_RESTRICTED = 4; // 0x4
field public static final int FLAG_IMMUTABLY_RESTRICTED = 16; // 0x10
field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
- field public static final int FLAG_INSTALLER_EXEMPT_IGNORED = 32; // 0x20
field public static final int FLAG_SOFT_RESTRICTED = 8; // 0x8
field public static final int PROTECTION_DANGEROUS = 1; // 0x1
field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
@@ -12902,6 +12902,7 @@
method public void reportShortcutUsed(String);
method public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender);
method public boolean setDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
+ method public void updateShortcutVisibility(@NonNull String, @Nullable byte[], boolean);
method public boolean updateShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
field public static final int FLAG_MATCH_CACHED = 8; // 0x8
field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
@@ -18568,6 +18569,23 @@
package android.hardware.display {
+ public final class DeviceProductInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getConnectionToSinkType();
+ method public int getManufactureWeek();
+ method public int getManufactureYear();
+ method @NonNull public String getManufacturerPnpId();
+ method public int getModelYear();
+ method @Nullable public String getName();
+ method @NonNull public String getProductId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CONNECTION_TO_SINK_BUILT_IN = 1; // 0x1
+ field public static final int CONNECTION_TO_SINK_DIRECT = 2; // 0x2
+ field public static final int CONNECTION_TO_SINK_TRANSITIVE = 3; // 0x3
+ field public static final int CONNECTION_TO_SINK_UNKNOWN = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.DeviceProductInfo> CREATOR;
+ }
+
public final class DisplayManager {
method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int);
method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
@@ -19293,8 +19311,8 @@
method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
}
- @Deprecated public static interface GnssAntennaInfo.Listener {
- method @Deprecated public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
+ public static interface GnssAntennaInfo.Listener {
+ method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
}
public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable {
@@ -19662,6 +19680,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
method public void addTestProvider(@NonNull String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties);
+ method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties, @NonNull java.util.Set<java.lang.String>);
method @Deprecated public void clearTestProviderEnabled(@NonNull String);
method @Deprecated public void clearTestProviderLocation(@NonNull String);
method @Deprecated public void clearTestProviderStatus(@NonNull String);
@@ -19682,7 +19701,7 @@
method public boolean hasProvider(@NonNull String);
method public boolean isLocationEnabled();
method public boolean isProviderEnabled(@NonNull String);
- method @Deprecated public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
+ method public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
@@ -19719,13 +19738,11 @@
method public void setTestProviderEnabled(@NonNull String, boolean);
method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
- method @Deprecated public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
+ method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
- field public static final String ACTION_GNSS_ANTENNA_INFOS_CHANGED = "android.location.action.GNSS_ANTENNA_INFOS_CHANGED";
field public static final String ACTION_GNSS_CAPABILITIES_CHANGED = "android.location.action.GNSS_CAPABILITIES_CHANGED";
- field public static final String EXTRA_GNSS_ANTENNA_INFOS = "android.location.extra.GNSS_ANTENNA_INFOS";
field public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
@@ -19868,7 +19885,6 @@
method public int getFlags();
method public int getUsage();
method public int getVolumeControlStream();
- method @NonNull public static String usageToString(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1
field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3
@@ -21301,8 +21317,8 @@
public static final class MediaCodecInfo.AudioCapabilities {
method public android.util.Range<java.lang.Integer> getBitrateRange();
method @NonNull public android.util.Range<java.lang.Integer>[] getInputChannelCountRanges();
- method public int getMaxInputChannelCount();
- method public int getMinInputChannelCount();
+ method @IntRange(from=1, to=255) public int getMaxInputChannelCount();
+ method @IntRange(from=1, to=255) public int getMinInputChannelCount();
method public android.util.Range<java.lang.Integer>[] getSupportedSampleRateRanges();
method public int[] getSupportedSampleRates();
method public boolean isSampleRateSupported(int);
@@ -22150,6 +22166,14 @@
field public static final String KEY_TILE_HEIGHT = "tile-height";
field public static final String KEY_TILE_WIDTH = "tile-width";
field public static final String KEY_TRACK_ID = "track-id";
+ field public static final String KEY_VIDEO_QP_B_MAX = "video-qp-b-max";
+ field public static final String KEY_VIDEO_QP_B_MIN = "video-qp-b-min";
+ field public static final String KEY_VIDEO_QP_I_MAX = "video-qp-i-max";
+ field public static final String KEY_VIDEO_QP_I_MIN = "video-qp-i-min";
+ field public static final String KEY_VIDEO_QP_MAX = "video-qp-max";
+ field public static final String KEY_VIDEO_QP_MIN = "video-qp-min";
+ field public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max";
+ field public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
field public static final String KEY_WIDTH = "width";
field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
field public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -24751,7 +24775,7 @@
method @NonNull public java.util.List<android.media.session.MediaController> getActiveSessions(@Nullable android.content.ComponentName);
method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
method public boolean isTrustedForMediaControl(@NonNull android.media.session.MediaSessionManager.RemoteUserInfo);
- method public void notifySession2Created(@NonNull android.media.Session2Token);
+ method @Deprecated public void notifySession2Created(@NonNull android.media.Session2Token);
method public void removeOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
method public void removeOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener);
}
@@ -25818,161 +25842,6 @@
package android.net {
- public class CaptivePortal implements android.os.Parcelable {
- method public int describeContents();
- method public void ignoreNetwork();
- method public void reportCaptivePortalDismissed();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
- }
-
- public class ConnectivityDiagnosticsManager {
- method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
- method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
- }
-
- public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
- ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
- method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
- method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
- method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
- }
-
- public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
- ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
- method public int describeContents();
- method @NonNull public android.os.PersistableBundle getAdditionalInfo();
- method @NonNull public android.net.LinkProperties getLinkProperties();
- method @NonNull public android.net.Network getNetwork();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
- method public long getReportTimestamp();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
- field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
- field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
- field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
- field public static final int NETWORK_PROBE_DNS = 4; // 0x4
- field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
- field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
- field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
- field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
- field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
- field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
- field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
- field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
- }
-
- public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
- ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
- method public int describeContents();
- method public int getDetectionMethod();
- method @NonNull public android.net.LinkProperties getLinkProperties();
- method @NonNull public android.net.Network getNetwork();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
- method public long getReportTimestamp();
- method @NonNull public android.os.PersistableBundle getStallDetails();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
- field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
- field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
- field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
- field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
- field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
- }
-
- public class ConnectivityManager {
- method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
- method public boolean bindProcessToNetwork(@Nullable android.net.Network);
- method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
- method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
- method @Deprecated public boolean getBackgroundDataSetting();
- method @Nullable public android.net.Network getBoundNetworkForProcess();
- method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
- method @Nullable public android.net.ProxyInfo getDefaultProxy();
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
- method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
- method @Nullable public byte[] getNetworkWatchlistConfigHash();
- method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
- method public int getRestrictBackgroundStatus();
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
- method public boolean isDefaultNetworkActive();
- method @Deprecated public static boolean isNetworkTypeValid(int);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
- method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
- method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
- method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
- method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
- method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
- method @Deprecated public void setNetworkPreference(int);
- method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
- method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
- method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
- field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
- field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
- field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
- field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
- field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
- field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
- field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
- field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
- field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
- field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
- field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
- field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
- field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
- field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
- field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
- field public static final String EXTRA_REASON = "reason";
- field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
- field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
- field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
- field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
- field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
- field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
- field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
- field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
- field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
- field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
- field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
- field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
- field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
- field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
- field @Deprecated public static final int TYPE_VPN = 17; // 0x11
- field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
- field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
- }
-
- public static class ConnectivityManager.NetworkCallback {
- ctor public ConnectivityManager.NetworkCallback();
- method public void onAvailable(@NonNull android.net.Network);
- method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
- method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
- method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
- method public void onLosing(@NonNull android.net.Network, int);
- method public void onLost(@NonNull android.net.Network);
- method public void onUnavailable();
- }
-
- public static interface ConnectivityManager.OnNetworkActiveListener {
- method public void onNetworkActive();
- }
-
public class Credentials {
ctor public Credentials(int, int, int);
method public int getGid();
@@ -25980,46 +25849,6 @@
method public int getUid();
}
- public class DhcpInfo implements android.os.Parcelable {
- ctor public DhcpInfo();
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
- field public int dns1;
- field public int dns2;
- field public int gateway;
- field public int ipAddress;
- field public int leaseDuration;
- field public int netmask;
- field public int serverAddress;
- }
-
- public final class DnsResolver {
- method @NonNull public static android.net.DnsResolver getInstance();
- method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
- method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
- method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
- method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
- field public static final int CLASS_IN = 1; // 0x1
- field public static final int ERROR_PARSE = 0; // 0x0
- field public static final int ERROR_SYSTEM = 1; // 0x1
- field public static final int FLAG_EMPTY = 0; // 0x0
- field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
- field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
- field public static final int FLAG_NO_RETRY = 1; // 0x1
- field public static final int TYPE_A = 1; // 0x1
- field public static final int TYPE_AAAA = 28; // 0x1c
- }
-
- public static interface DnsResolver.Callback<T> {
- method public void onAnswer(@NonNull T, int);
- method public void onError(@NonNull android.net.DnsResolver.DnsException);
- }
-
- public static class DnsResolver.DnsException extends java.lang.Exception {
- field public final int code;
- }
-
public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile {
method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms();
method public int getMaxMtu();
@@ -26049,21 +25878,6 @@
method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo);
}
- public class InetAddresses {
- method public static boolean isNumericAddress(@NonNull String);
- method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
- }
-
- public final class IpPrefix implements android.os.Parcelable {
- method public boolean contains(@NonNull java.net.InetAddress);
- method public int describeContents();
- method @NonNull public java.net.InetAddress getAddress();
- method @IntRange(from=0, to=128) public int getPrefixLength();
- method @NonNull public byte[] getRawAddress();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
- }
-
public final class IpSecAlgorithm implements android.os.Parcelable {
ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]);
ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int);
@@ -26132,45 +25946,6 @@
method @NonNull public android.net.IpSecTransform.Builder setIpv4Encapsulation(@NonNull android.net.IpSecManager.UdpEncapsulationSocket, int);
}
- public class LinkAddress implements android.os.Parcelable {
- method public int describeContents();
- method public java.net.InetAddress getAddress();
- method public int getFlags();
- method @IntRange(from=0, to=128) public int getPrefixLength();
- method public int getScope();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
- }
-
- public final class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties();
- method public boolean addRoute(@NonNull android.net.RouteInfo);
- method public void clear();
- method public int describeContents();
- method @Nullable public java.net.Inet4Address getDhcpServerAddress();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
- method @Nullable public String getDomains();
- method @Nullable public android.net.ProxyInfo getHttpProxy();
- method @Nullable public String getInterfaceName();
- method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
- method public int getMtu();
- method @Nullable public android.net.IpPrefix getNat64Prefix();
- method @Nullable public String getPrivateDnsServerName();
- method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
- method public boolean isPrivateDnsActive();
- method public boolean isWakeOnLanSupported();
- method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
- method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
- method public void setDomains(@Nullable String);
- method public void setHttpProxy(@Nullable android.net.ProxyInfo);
- method public void setInterfaceName(@Nullable String);
- method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
- method public void setMtu(int);
- method public void setNat64Prefix(@Nullable android.net.IpPrefix);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
- }
-
public class LocalServerSocket implements java.io.Closeable {
ctor public LocalServerSocket(String) throws java.io.IOException;
ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -26226,24 +26001,6 @@
enum_constant public static final android.net.LocalSocketAddress.Namespace RESERVED;
}
- public final class MacAddress implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
- method @NonNull public static android.net.MacAddress fromString(@NonNull String);
- method public int getAddressType();
- method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
- method public boolean isLocallyAssigned();
- method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
- method @NonNull public byte[] toByteArray();
- method @NonNull public String toOuiString();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.net.MacAddress BROADCAST_ADDRESS;
- field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
- field public static final int TYPE_BROADCAST = 3; // 0x3
- field public static final int TYPE_MULTICAST = 2; // 0x2
- field public static final int TYPE_UNICAST = 1; // 0x1
- }
-
public class MailTo {
method public String getBody();
method public String getCc();
@@ -26255,139 +26012,6 @@
field public static final String MAILTO_SCHEME = "mailto:";
}
- public class Network implements android.os.Parcelable {
- method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
- method public void bindSocket(java.net.Socket) throws java.io.IOException;
- method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
- method public int describeContents();
- method public static android.net.Network fromNetworkHandle(long);
- method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
- method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
- method public long getNetworkHandle();
- method public javax.net.SocketFactory getSocketFactory();
- method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
- method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities();
- ctor public NetworkCapabilities(android.net.NetworkCapabilities);
- method public int describeContents();
- method public int getLinkDownstreamBandwidthKbps();
- method public int getLinkUpstreamBandwidthKbps();
- method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
- method public int getOwnerUid();
- method public int getSignalStrength();
- method @Nullable public android.net.TransportInfo getTransportInfo();
- method public boolean hasCapability(int);
- method public boolean hasTransport(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
- field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
- field public static final int NET_CAPABILITY_CBS = 5; // 0x5
- field public static final int NET_CAPABILITY_DUN = 2; // 0x2
- field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
- field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
- field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
- field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
- field public static final int NET_CAPABILITY_IA = 7; // 0x7
- field public static final int NET_CAPABILITY_IMS = 4; // 0x4
- field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
- field public static final int NET_CAPABILITY_MCX = 23; // 0x17
- field public static final int NET_CAPABILITY_MMS = 0; // 0x0
- field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
- field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
- field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
- field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
- field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
- field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
- field public static final int NET_CAPABILITY_RCS = 8; // 0x8
- field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
- field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19
- field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
- field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
- field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
- field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
- field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
- field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
- field public static final int TRANSPORT_CELLULAR = 0; // 0x0
- field public static final int TRANSPORT_ETHERNET = 3; // 0x3
- field public static final int TRANSPORT_LOWPAN = 6; // 0x6
- field public static final int TRANSPORT_VPN = 4; // 0x4
- field public static final int TRANSPORT_WIFI = 1; // 0x1
- field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
- }
-
- @Deprecated public class NetworkInfo implements android.os.Parcelable {
- ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String);
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
- method @Deprecated public String getExtraInfo();
- method @Deprecated public String getReason();
- method @Deprecated public android.net.NetworkInfo.State getState();
- method @Deprecated public int getSubtype();
- method @Deprecated public String getSubtypeName();
- method @Deprecated public int getType();
- method @Deprecated public String getTypeName();
- method @Deprecated public boolean isAvailable();
- method @Deprecated public boolean isConnected();
- method @Deprecated public boolean isConnectedOrConnecting();
- method @Deprecated public boolean isFailover();
- method @Deprecated public boolean isRoaming();
- method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
- }
-
- @Deprecated public enum NetworkInfo.DetailedState {
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
- }
-
- @Deprecated public enum NetworkInfo.State {
- enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
- method public int describeContents();
- method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
- method public boolean hasCapability(int);
- method public boolean hasTransport(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
- }
-
- public static class NetworkRequest.Builder {
- ctor public NetworkRequest.Builder();
- method public android.net.NetworkRequest.Builder addCapability(int);
- method public android.net.NetworkRequest.Builder addTransportType(int);
- method public android.net.NetworkRequest build();
- method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
- method public android.net.NetworkRequest.Builder removeCapability(int);
- method public android.net.NetworkRequest.Builder removeTransportType(int);
- method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
- method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
- }
-
public abstract class NetworkSpecifier {
ctor public NetworkSpecifier();
}
@@ -26404,44 +26028,6 @@
field public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6; // 0x6
}
- public final class Proxy {
- ctor public Proxy();
- method @Deprecated public static String getDefaultHost();
- method @Deprecated public static int getDefaultPort();
- method @Deprecated public static String getHost(android.content.Context);
- method @Deprecated public static int getPort(android.content.Context);
- field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
- field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
- }
-
- public class ProxyInfo implements android.os.Parcelable {
- ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
- method public static android.net.ProxyInfo buildDirectProxy(String, int);
- method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
- method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
- method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
- method public int describeContents();
- method public String[] getExclusionList();
- method public String getHost();
- method public android.net.Uri getPacFileUrl();
- method public int getPort();
- method public boolean isValid();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
- }
-
- public final class RouteInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.IpPrefix getDestination();
- method @Nullable public java.net.InetAddress getGateway();
- method @Nullable public String getInterface();
- method public boolean hasGateway();
- method public boolean isDefaultRoute();
- method public boolean matches(java.net.InetAddress);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
- }
-
@Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
ctor @Deprecated public SSLCertificateSocketFactory(int);
method @Deprecated public java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException;
@@ -26467,30 +26053,6 @@
ctor public SSLSessionCache(android.content.Context);
}
- public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- method public final void close();
- method public final void start(@IntRange(from=0xa, to=0xe10) int);
- method public final void stop();
- field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
- field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0
- field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
- field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
- field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
- field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
- field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
- field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
- field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
- field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2
- }
-
- public static class SocketKeepalive.Callback {
- ctor public SocketKeepalive.Callback();
- method public void onDataReceived();
- method public void onError(int);
- method public void onStarted();
- method public void onStopped();
- }
-
public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
method public int describeContents();
method public int getSubscriptionId();
@@ -26548,9 +26110,6 @@
field public static final int UNSUPPORTED = -1; // 0xffffffff
}
- public interface TransportInfo {
- }
-
public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
method public abstract android.net.Uri.Builder buildUpon();
method public int compareTo(android.net.Uri);
@@ -31923,10 +31482,10 @@
method public static android.content.Intent createUserCreationIntent(@Nullable String, @Nullable String, @Nullable String, @Nullable android.os.PersistableBundle);
method @WorkerThread public android.os.Bundle getApplicationRestrictions(String);
method public long getSerialNumberForUser(android.os.UserHandle);
- method @RequiresPermission("android.permission.MANAGE_USERS") public int getUserCount();
+ method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public int getUserCount();
method public long getUserCreationTime(android.os.UserHandle);
method public android.os.UserHandle getUserForSerialNumber(long);
- method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}, conditional=true) public String getUserName();
+ method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, "android.permission.CREATE_USERS"}, conditional=true) public String getUserName();
method public java.util.List<android.os.UserHandle> getUserProfiles();
method public android.os.Bundle getUserRestrictions();
method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
@@ -38538,6 +38097,7 @@
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types";
+ field public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types";
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
@@ -40248,7 +39808,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle);
- method public boolean hasCompanionInCallServiceAccess();
+ method public boolean hasManageOngoingCallsPermission();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInCall();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInManagedCall();
method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
@@ -40875,6 +40435,7 @@
}
public static final class CarrierConfigManager.Apn {
+ field @Deprecated public static final String KEY_PREFIX = "apn.";
field public static final String KEY_SETTINGS_DEFAULT_PROTOCOL_STRING = "apn.settings_default_protocol_string";
field public static final String KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING = "apn.settings_default_roaming_protocol_string";
field public static final String PROTOCOL_IPV4 = "IP";
@@ -40899,7 +40460,7 @@
}
public static final class CarrierConfigManager.ImsServiceEntitlement {
- field public static final String KEY_AES_URL_STRING = "imsserviceentitlement.aes_url_string";
+ field public static final String KEY_ENTITLEMENT_SERVER_URL_STRING = "imsserviceentitlement.entitlement_server_url_string";
field public static final String KEY_PREFIX = "imsserviceentitlement.";
}
@@ -42127,7 +41688,6 @@
public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public android.os.IBinder getLiveToken();
method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos();
method public boolean isReportingRequestedWhileIdle();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -46705,6 +46265,7 @@
method public long getAppVsyncOffsetNanos();
method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
method @Nullable public android.view.DisplayCutout getCutout();
+ method @Nullable public android.hardware.display.DeviceProductInfo getDeviceProductInfo();
method public int getDisplayId();
method public int getFlags();
method public android.view.Display.HdrCapabilities getHdrCapabilities();
@@ -48028,6 +47589,32 @@
method public void onScaleEnd(android.view.ScaleGestureDetector);
}
+ @UiThread public interface ScrollCaptureCallback {
+ method public void onScrollCaptureEnd(@NonNull Runnable);
+ method public void onScrollCaptureImageRequest(@NonNull android.view.ScrollCaptureSession, @NonNull android.os.CancellationSignal, @NonNull android.graphics.Rect, @NonNull java.util.function.Consumer<android.graphics.Rect>);
+ method public void onScrollCaptureSearch(@NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.graphics.Rect>);
+ method public void onScrollCaptureStart(@NonNull android.view.ScrollCaptureSession, @NonNull android.os.CancellationSignal, @NonNull Runnable);
+ }
+
+ public class ScrollCaptureSession {
+ ctor public ScrollCaptureSession(@NonNull android.view.Surface, @NonNull android.graphics.Rect, @NonNull android.graphics.Point);
+ method @NonNull public android.graphics.Point getPositionInWindow();
+ method @NonNull public android.graphics.Rect getScrollBounds();
+ method @NonNull public android.view.Surface getSurface();
+ }
+
+ public final class ScrollCaptureTarget {
+ ctor public ScrollCaptureTarget(@NonNull android.view.View, @NonNull android.graphics.Rect, @NonNull android.graphics.Point, @NonNull android.view.ScrollCaptureCallback);
+ method @NonNull public android.view.ScrollCaptureCallback getCallback();
+ method @NonNull public android.view.View getContainingView();
+ method public int getHint();
+ method @NonNull public android.graphics.Rect getLocalVisibleRect();
+ method @NonNull public android.graphics.Point getPositionInWindow();
+ method @Nullable public android.graphics.Rect getScrollBounds();
+ method public void setScrollBounds(@Nullable android.graphics.Rect);
+ method @UiThread public void updatePositionInWindow();
+ }
+
public class SearchEvent {
ctor public SearchEvent(android.view.InputDevice);
method public android.view.InputDevice getInputDevice();
@@ -48354,6 +47941,7 @@
method public void dispatchProvideStructure(android.view.ViewStructure);
method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
+ method public void dispatchScrollCaptureSearch(@NonNull android.graphics.Rect, @NonNull android.graphics.Point, @NonNull java.util.function.Consumer<android.view.ScrollCaptureTarget>);
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
@@ -48513,6 +48101,7 @@
method public int getScrollBarFadeDuration();
method public int getScrollBarSize();
method public int getScrollBarStyle();
+ method public int getScrollCaptureHint();
method public int getScrollIndicators();
method public final int getScrollX();
method public final int getScrollY();
@@ -48681,6 +48270,7 @@
method public void onRtlPropertiesChanged(int);
method @CallSuper @Nullable protected android.os.Parcelable onSaveInstanceState();
method public void onScreenStateChanged(int);
+ method public void onScrollCaptureSearch(@NonNull android.graphics.Rect, @NonNull android.graphics.Point, @NonNull java.util.function.Consumer<android.view.ScrollCaptureTarget>);
method protected void onScrollChanged(int, int, int, int);
method protected boolean onSetAlpha(int);
method protected void onSizeChanged(int, int, int, int);
@@ -48863,6 +48453,8 @@
method public void setScrollBarFadeDuration(int);
method public void setScrollBarSize(int);
method public void setScrollBarStyle(int);
+ method public final void setScrollCaptureCallback(@Nullable android.view.ScrollCaptureCallback);
+ method public void setScrollCaptureHint(int);
method public void setScrollContainer(boolean);
method public void setScrollIndicators(int);
method public void setScrollIndicators(int, int);
@@ -49041,6 +48633,10 @@
field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
field public static final int SCROLL_AXIS_NONE = 0; // 0x0
field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_CAPTURE_HINT_AUTO = 0; // 0x0
+ field public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 1; // 0x1
+ field public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 4; // 0x4
+ field public static final int SCROLL_CAPTURE_HINT_INCLUDE = 2; // 0x2
field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
field public static final int SCROLL_INDICATOR_END = 32; // 0x20
field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
@@ -49825,6 +49421,7 @@
method public abstract boolean performContextMenuIdentifierAction(int, int);
method public abstract boolean performPanelIdentifierAction(int, int, int);
method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
+ method public void registerScrollCaptureCallback(@NonNull android.view.ScrollCaptureCallback);
method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
method public boolean requestFeature(int);
method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
@@ -49904,6 +49501,7 @@
method public abstract void takeKeyEvents(boolean);
method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
method public abstract void togglePanel(int, android.view.KeyEvent);
+ method public void unregisterScrollCaptureCallback(@NonNull android.view.ScrollCaptureCallback);
field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
@@ -50144,9 +49742,12 @@
}
public interface WindowManager extends android.view.ViewManager {
+ method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
method @Deprecated public android.view.Display getDefaultDisplay();
method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
+ method public default boolean isCrossWindowBlurEnabled();
+ method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void removeViewImmediate(android.view.View);
}
@@ -50171,12 +49772,14 @@
method public final int copyFrom(android.view.WindowManager.LayoutParams);
method public String debug(String);
method public int describeContents();
+ method public int getBlurBehindRadius();
method public int getColorMode();
method public int getFitInsetsSides();
method public int getFitInsetsTypes();
method public final CharSequence getTitle();
method public boolean isFitInsetsIgnoringVisibility();
method public static boolean mayUseInputMethod(int);
+ method public void setBlurBehindRadius(@IntRange(from=0) int);
method public void setColorMode(int);
method public void setFitInsetsIgnoringVisibility(boolean);
method public void setFitInsetsSides(int);
@@ -50287,7 +49890,6 @@
field @Deprecated public static final int TYPE_TOAST = 2005; // 0x7d5
field public static final int TYPE_WALLPAPER = 2013; // 0x7dd
field public float alpha;
- field public int blurBehindRadius;
field public float buttonBrightness;
field public float dimAmount;
field public int flags;
@@ -51714,7 +51316,6 @@
method public int describeContents();
method public void dump(android.util.Printer, String);
method public android.content.ComponentName getComponent();
- method public int getConfigChanges();
method public String getId();
method public int getIsDefaultResourceId();
method public String getPackageName();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index dd9582f..7ea7d61 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -163,67 +163,14 @@
package android.net {
- public final class ConnectivityFrameworkInitializer {
- method public static void registerServiceWrappers();
- }
-
- public class ConnectivityManager {
- 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, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
- }
-
public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
method public int getResourceId();
}
- public final class NetworkAgentConfig implements android.os.Parcelable {
- method @Nullable public String getSubscriberId();
- }
-
- public static final class NetworkAgentConfig.Builder {
- method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- field public static final int TRANSPORT_TEST = 7; // 0x7
- }
-
public class NetworkWatchlistManager {
method @Nullable public byte[] getWatchlistConfigHash();
}
- public final class Proxy {
- method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
- }
-
- public final class TcpRepairWindow {
- ctor public TcpRepairWindow(int, int, int, int, int, int);
- field public final int maxWindow;
- field public final int rcvWnd;
- field public final int rcvWndScale;
- field public final int rcvWup;
- field public final int sndWl1;
- field public final int sndWnd;
- }
-
- public final class TestNetworkInterface implements android.os.Parcelable {
- ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
- method public int describeContents();
- method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
- method @NonNull public String getInterfaceName();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
- }
-
- public class TestNetworkManager {
- method @NonNull public android.net.TestNetworkInterface createTapInterface();
- method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
- method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
- method public void teardownTestNetwork(@NonNull android.net.Network);
- field public static final String TEST_TAP_PREFIX = "testtap";
- }
-
public final class UnderlyingNetworkInfo implements android.os.Parcelable {
ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>);
method public int describeContents();
@@ -234,14 +181,6 @@
field @NonNull public final java.util.List<java.lang.String> underlyingIfaces;
}
- public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
- ctor public VpnTransportInfo(int);
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
- field public final int type;
- }
-
}
package android.os {
@@ -275,6 +214,16 @@
}
+package android.os.storage {
+
+ public class StorageManager {
+ method public void notifyAppIoBlocked(@NonNull String, int, int, int);
+ method public void notifyAppIoResumed(@NonNull String, int, int, int);
+ field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 0; // 0x0
+ }
+
+}
+
package android.provider {
public final class DeviceConfig {
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 990388a..a99178d 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -241,12 +241,6 @@
package android.net {
- public class ConnectivityManager {
- method @Deprecated public boolean requestRouteToHost(int, int);
- method @Deprecated public int startUsingNetworkFeature(int, String);
- method @Deprecated public int stopUsingNetworkFeature(int, String);
- }
-
@Deprecated public class NetworkBadging {
method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
field public static final int BADGING_4K = 30; // 0x1e
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0536014..c7744a4 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -27,6 +27,7 @@
field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
+ field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
field public static final String BACKUP = "android.permission.BACKUP";
field public static final String BATTERY_PREDICTION = "android.permission.BATTERY_PREDICTION";
field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
@@ -176,6 +177,7 @@
field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
+ field public static final String OBSERVE_SENSOR_PRIVACY = "android.permission.OBSERVE_SENSOR_PRIVACY";
field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
@@ -214,6 +216,7 @@
field public static final String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY";
field public static final String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
field public static final String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE";
+ field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String RECOVERY = "android.permission.RECOVERY";
field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
@@ -352,6 +355,7 @@
field public static final int config_systemContacts = 17039403; // 0x104002b
field public static final int config_systemGallery = 17039399; // 0x1040027
field public static final int config_systemShell = 17039402; // 0x104002a
+ field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
}
public static final class R.style {
@@ -641,8 +645,8 @@
method public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
method public void setDontSendToRestrictedApps(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
- method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(int, long);
+ method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppAllowlist(long, int, int, @Nullable String);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
method public android.os.Bundle toBundle();
}
@@ -853,13 +857,6 @@
method public void onVrStateChanged(boolean);
}
- public final class WallpaperColors implements android.os.Parcelable {
- ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
- method public int getColorHints();
- field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
- field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
- }
-
public final class WallpaperInfo implements android.os.Parcelable {
method public boolean supportsAmbientMode();
}
@@ -957,6 +954,9 @@
package android.app.assist {
+ public class ActivityId {
+ }
+
public static class AssistStructure.ViewNode {
ctor public AssistStructure.ViewNode();
}
@@ -2461,10 +2461,10 @@
}
public static class PackageInstaller.Session implements java.io.Closeable {
- method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
+ method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
- method @Nullable @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public android.content.pm.DataLoaderParams getDataLoaderParams();
- method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void removeFile(int, @NonNull String);
+ method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams();
+ method public void removeFile(int, @NonNull String);
}
public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
@@ -2485,7 +2485,7 @@
public static class PackageInstaller.SessionParams implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
method @Deprecated public void setAllowDowngrade(boolean);
- method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.USE_INSTALLER_V2"}) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
+ method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
method public void setDontKillApp(boolean);
method public void setEnableRollback(boolean);
method public void setEnableRollback(boolean, int);
@@ -2550,10 +2550,11 @@
field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
+ field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
- field public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
field @Deprecated public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
field public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = "android.software.incremental_delivery_version";
+ field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final String FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION = "android.hardware.telephony.ims.singlereg";
@@ -2565,7 +2566,6 @@
field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800
- field public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 262144; // 0x40000
field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000
field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
@@ -2751,6 +2751,15 @@
package android.content.pm.verify.domain {
+ public final class DomainOwner implements android.os.Parcelable {
+ ctor public DomainOwner(@NonNull String, boolean);
+ method public int describeContents();
+ method @NonNull public String getPackageName();
+ method public boolean isOverrideable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainOwner> CREATOR;
+ }
+
public final class DomainVerificationInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
@@ -2763,6 +2772,7 @@
public interface DomainVerificationManager {
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) public android.content.pm.verify.domain.DomainVerificationInfo getDomainVerificationInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public android.content.pm.verify.domain.DomainVerificationUserSelection getDomainVerificationUserSelection(@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.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> getValidVerificationPackageNames();
method public static boolean isStateModifiable(int);
method public static boolean isStateVerified(int);
@@ -2784,13 +2794,16 @@
public final class DomainVerificationUserSelection implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public java.util.Map<java.lang.String,java.lang.Boolean> getHostToUserSelectionMap();
+ method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
method @NonNull public java.util.UUID getIdentifier();
method @NonNull public String getPackageName();
method @NonNull public android.os.UserHandle getUser();
method @NonNull public boolean isLinkHandlingAllowed();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserSelection> CREATOR;
+ field public static final int DOMAIN_STATE_NONE = 0; // 0x0
+ field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
+ field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
}
}
@@ -2874,7 +2887,7 @@
}
public class FontManager {
- method @Nullable public android.text.FontConfig getFontConfig();
+ method @NonNull public android.text.FontConfig getFontConfig();
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.graphics.fonts.FontFileUpdateRequest, @IntRange(from=0) int);
method @Deprecated @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int);
@@ -2908,6 +2921,22 @@
method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
}
+ public final class SensorPrivacyManager {
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(int);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ }
+
+ public static interface SensorPrivacyManager.OnSensorPrivacyChangedListener {
+ method public void onSensorPrivacyChanged(boolean);
+ }
+
+ public static class SensorPrivacyManager.Sensors {
+ field public static final int CAMERA = 2; // 0x2
+ field public static final int MICROPHONE = 1; // 0x1
+ }
+
}
package android.hardware.biometrics {
@@ -5053,9 +5082,10 @@
}
public static class AudioTrack.TunerConfiguration {
- ctor @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public AudioTrack.TunerConfiguration(@IntRange(from=1) int, @IntRange(from=1) int);
+ ctor @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public AudioTrack.TunerConfiguration(@IntRange(from=0) int, @IntRange(from=1) int);
method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getContentId();
method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getSyncId();
+ field public static final int CONTENT_ID_NONE = 0; // 0x0
}
public class HwAudioSource {
@@ -7063,102 +7093,6 @@
package android.net {
- public class CaptivePortal implements android.os.Parcelable {
- method public void logEvent(int, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
- method public void useNetwork();
- field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
- field public static final int APP_RETURN_DISMISSED = 0; // 0x0
- field public static final int APP_RETURN_UNWANTED = 1; // 0x1
- field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
- }
-
- public final class CaptivePortalData implements android.os.Parcelable {
- method public int describeContents();
- method public long getByteLimit();
- method public long getExpiryTimeMillis();
- method public long getRefreshTimeMillis();
- method @Nullable public android.net.Uri getUserPortalUrl();
- method public int getUserPortalUrlSource();
- method @Nullable public String getVenueFriendlyName();
- method @Nullable public android.net.Uri getVenueInfoUrl();
- method public int getVenueInfoUrlSource();
- method public boolean isCaptive();
- method public boolean isSessionExtendable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
- field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
- field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
- }
-
- public static class CaptivePortalData.Builder {
- ctor public CaptivePortalData.Builder();
- ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
- method @NonNull public android.net.CaptivePortalData build();
- method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
- method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
- method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
- }
-
- public class ConnectivityManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
- method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void unregisterQosCallback(@NonNull android.net.QosCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
- field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
- field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
- field public static final int TYPE_NONE = -1; // 0xffffffff
- field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
- field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
- }
-
- public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
- method public void onComplete();
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
- ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
- method @Deprecated public void onTetheringFailed();
- method @Deprecated public void onTetheringStarted();
- }
-
- @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
- method @Deprecated public void onTetheringEntitlementResult(int);
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
- ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
- method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
- }
-
public class DnsResolverServiceManager {
method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public static android.os.IBinder getService(@NonNull android.content.Context);
}
@@ -7176,48 +7110,6 @@
method public void release();
}
- public final class InvalidPacketException extends java.lang.Exception {
- ctor public InvalidPacketException(int);
- method public int getError();
- field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
- field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
- field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
- }
-
- public final class IpConfiguration implements android.os.Parcelable {
- ctor public IpConfiguration();
- ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
- method public int describeContents();
- method @Nullable public android.net.ProxyInfo getHttpProxy();
- method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
- method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
- method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
- method public void setHttpProxy(@Nullable android.net.ProxyInfo);
- method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
- method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
- method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
- }
-
- public enum IpConfiguration.IpAssignment {
- enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
- enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
- enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
- }
-
- public enum IpConfiguration.ProxySettings {
- enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
- enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
- }
-
- public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- ctor public IpPrefix(@NonNull String);
- }
-
public final class IpSecManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
@@ -7235,68 +7127,6 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
}
- public class KeepalivePacketData {
- ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
- method @NonNull public java.net.InetAddress getDstAddress();
- method public int getDstPort();
- method @NonNull public byte[] getPacket();
- method @NonNull public java.net.InetAddress getSrcAddress();
- method public int getSrcPort();
- }
-
- public class LinkAddress implements android.os.Parcelable {
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- ctor public LinkAddress(@NonNull String);
- ctor public LinkAddress(@NonNull String, int, int);
- method public long getDeprecationTime();
- method public long getExpirationTime();
- method public boolean isGlobalPreferred();
- method public boolean isIpv4();
- method public boolean isIpv6();
- method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
- field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
- field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
- }
-
- public final class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties(@Nullable android.net.LinkProperties);
- ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
- method public boolean addDnsServer(@NonNull java.net.InetAddress);
- method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean addPcscfServer(@NonNull java.net.InetAddress);
- method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
- method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
- method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
- method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
- method @Nullable public android.net.Uri getCaptivePortalApiUrl();
- method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
- method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
- method @Nullable public String getTcpBufferSizes();
- method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
- method public boolean hasGlobalIpv6Address();
- method public boolean hasIpv4Address();
- method public boolean hasIpv4DefaultRoute();
- method public boolean hasIpv4DnsServer();
- method public boolean hasIpv6DefaultRoute();
- method public boolean hasIpv6DnsServer();
- method public boolean isIpv4Provisioned();
- method public boolean isIpv6Provisioned();
- method public boolean isProvisioned();
- method public boolean isReachable(@NonNull java.net.InetAddress);
- method public boolean removeDnsServer(@NonNull java.net.InetAddress);
- method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean removeRoute(@NonNull android.net.RouteInfo);
- method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
- method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
- method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
- method public void setPrivateDnsServerName(@Nullable String);
- method public void setTcpBufferSizes(@Nullable String);
- method public void setUsePrivateDns(boolean);
- method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
- }
-
public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
ctor public MatchAllNetworkSpecifier();
method public int describeContents();
@@ -7304,104 +7134,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR;
}
- public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
- ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
- }
-
- public class Network implements android.os.Parcelable {
- ctor public Network(@NonNull android.net.Network);
- method public int getNetId();
- method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
- }
-
- public abstract class NetworkAgent {
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
- method @Nullable public android.net.Network getNetwork();
- method public void markConnected();
- method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
- method public void onAutomaticReconnectDisabled();
- method public void onNetworkUnwanted();
- method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
- method public void onQosCallbackUnregistered(int);
- method public void onRemoveKeepalivePacketFilter(int);
- method public void onSaveAcceptUnvalidated(boolean);
- method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
- method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
- method public void onStopSocketKeepalive(int);
- method public void onValidationStatus(int, @Nullable android.net.Uri);
- method @NonNull public android.net.Network register();
- method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
- method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
- method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
- method public final void sendQosCallbackError(int, int);
- method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
- method public final void sendQosSessionLost(int, int);
- method public final void sendSocketKeepaliveEvent(int, int);
- method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
- method public void unregister();
- field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
- field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
- }
-
- public final class NetworkAgentConfig implements android.os.Parcelable {
- method public int describeContents();
- method public int getLegacyType();
- method @NonNull public String getLegacyTypeName();
- method public boolean isExplicitlySelected();
- method public boolean isPartialConnectivityAcceptable();
- method public boolean isUnvalidatedConnectivityAcceptable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
- }
-
- public static final class NetworkAgentConfig.Builder {
- ctor public NetworkAgentConfig.Builder();
- method @NonNull public android.net.NetworkAgentConfig build();
- method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
- method @NonNull public int[] getAdministratorUids();
- method @Nullable public String getSsid();
- method @NonNull public int[] getTransportTypes();
- method public boolean isPrivateDnsBroken();
- method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
- field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
- field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
- field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
- field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
- field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
- }
-
- public static final class NetworkCapabilities.Builder {
- ctor public NetworkCapabilities.Builder();
- ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
- method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
- method @NonNull public android.net.NetworkCapabilities build();
- method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
- method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
- method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
- }
-
public class NetworkKey implements android.os.Parcelable {
ctor public NetworkKey(android.net.WifiKey);
method @Nullable public static android.net.NetworkKey createFromScanResult(@NonNull android.net.wifi.ScanResult);
@@ -7413,15 +7145,6 @@
field public final android.net.WifiKey wifiKey;
}
- public class NetworkProvider {
- ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
- method public int getProviderId();
- method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
- method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
- field public static final int ID_NONE = -1; // 0xffffffff
- }
-
public abstract class NetworkRecommendationProvider {
ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
method public final android.os.IBinder getBinder();
@@ -7431,15 +7154,6 @@
public class NetworkReleasedException extends java.lang.Exception {
}
- public class NetworkRequest implements android.os.Parcelable {
- method @Nullable public String getRequestorPackageName();
- method public int getRequestorUid();
- }
-
- public static class NetworkRequest.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
- }
-
public class NetworkScoreManager {
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
@@ -7564,16 +7278,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
}
- public final class RouteInfo implements android.os.Parcelable {
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
- method public int getMtu();
- method public int getType();
- field public static final int RTN_THROW = 9; // 0x9
- field public static final int RTN_UNICAST = 1; // 0x1
- field public static final int RTN_UNREACHABLE = 7; // 0x7
- }
-
public class RssiCurve implements android.os.Parcelable {
ctor public RssiCurve(int, int, byte[]);
ctor public RssiCurve(int, int, byte[], int);
@@ -7605,53 +7309,12 @@
field public final android.net.RssiCurve rssiCurve;
}
- public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- field public static final int SUCCESS = 0; // 0x0
- }
-
public class SocketLocalAddressChangedException extends java.lang.Exception {
}
public class SocketNotBoundException extends java.lang.Exception {
}
- public final class StaticIpConfiguration implements android.os.Parcelable {
- ctor public StaticIpConfiguration();
- ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- method public void addDnsServer(@NonNull java.net.InetAddress);
- method public void clear();
- method public int describeContents();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
- method @Nullable public String getDomains();
- method @Nullable public java.net.InetAddress getGateway();
- method @Nullable public android.net.LinkAddress getIpAddress();
- method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
- }
-
- public static final class StaticIpConfiguration.Builder {
- ctor public StaticIpConfiguration.Builder();
- method @NonNull public android.net.StaticIpConfiguration build();
- method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
- method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
- method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
- method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
- }
-
- public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
- ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
- field public final int ipTos;
- field public final int ipTtl;
- field public final int tcpAck;
- field public final int tcpSeq;
- field public final int tcpWindow;
- field public final int tcpWindowScale;
- }
-
public class TrafficStats {
method public static void setThreadStatsTagApp();
method public static void setThreadStatsTagBackup();
@@ -7664,11 +7327,6 @@
field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
}
- public interface TransportInfo {
- method public default boolean hasLocationSensitiveFields();
- method @NonNull public default android.net.TransportInfo makeCopy(boolean);
- }
-
public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
method @NonNull public String toSafeString();
}
@@ -7692,23 +7350,6 @@
}
-package android.net.apf {
-
- public final class ApfCapabilities implements android.os.Parcelable {
- ctor public ApfCapabilities(int, int, int);
- method public int describeContents();
- method public static boolean getApfDrop8023Frames();
- method @NonNull public static int[] getApfEtherTypeBlackList();
- method public boolean hasDataAccess();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
- field public final int apfPacketFormat;
- field public final int apfVersionSupported;
- field public final int maximumApfProgramSize;
- }
-
-}
-
package android.net.metrics {
@Deprecated public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -7903,19 +7544,6 @@
}
-package android.net.util {
-
- public final class SocketUtils {
- method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
- method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
- method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
- method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
- method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
- method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
- }
-
-}
-
package android.net.vcn {
public class VcnManager {
@@ -8607,11 +8235,18 @@
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @Nullable String);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String);
field public static final int EVENT_MMS = 2; // 0x2
field public static final int EVENT_SMS = 1; // 0x1
field public static final int EVENT_UNSPECIFIED = 0; // 0x0
+ field public static final int REASON_ACTIVITY_RECOGNITION = 102; // 0x66
+ field public static final int REASON_GEOFENCING = 100; // 0x64
+ field public static final int REASON_OTHER = 1; // 0x1
+ field public static final int REASON_PUSH_MESSAGING = 101; // 0x65
+ field public static final int REASON_UNKNOWN = 0; // 0x0
field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
}
@@ -8760,13 +8395,13 @@
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getRestrictedProfileParent();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public long[] getSerialNumbersOfUsers(boolean);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
@@ -9204,6 +8839,7 @@
field public static final String NAMESPACE_BIOMETRICS = "biometrics";
field public static final String NAMESPACE_BLOBSTORE = "blobstore";
field public static final String NAMESPACE_BLUETOOTH = "bluetooth";
+ field public static final String NAMESPACE_CLIPBOARD = "clipboard";
field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
field @Deprecated public static final String NAMESPACE_DEX_BOOT = "dex_boot";
@@ -10427,10 +10063,10 @@
public abstract class ExternalStorageService extends android.app.Service {
ctor public ExternalStorageService();
+ method public void onAnrDelayStarted(@NonNull String, int, int, int);
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onEndSession(@NonNull String) throws java.io.IOException;
method public void onFreeCache(@NonNull java.util.UUID, long) throws java.io.IOException;
- method public long onGetAnrDelayMillis(@NonNull String, int);
method public abstract void onStartSession(@NonNull String, int, @NonNull android.os.ParcelFileDescriptor, @NonNull java.io.File, @NonNull java.io.File) throws java.io.IOException;
method public abstract void onVolumeStateChanged(@NonNull android.os.storage.StorageVolume) throws java.io.IOException;
field public static final int FLAG_SESSION_ATTRIBUTE_INDEXABLE = 2; // 0x2
@@ -10628,7 +10264,7 @@
public abstract class HotwordDetectionService extends android.app.Service {
ctor public HotwordDetectionService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public void onDetectFromDspSource(int, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
+ method public void onDetectFromDspSource(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";
}
@@ -11131,6 +10767,10 @@
field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool";
}
+ public static final class CarrierConfigManager.Ims {
+ field public static final String KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY = "ims.publish_service_desc_feature_tag_map_override_string_array";
+ }
+
public static final class CarrierConfigManager.Wifi {
field public static final String KEY_AVOID_5GHZ_SOFTAP_FOR_LAA_BOOL = "wifi.avoid_5ghz_softap_for_laa_bool";
field public static final String KEY_AVOID_5GHZ_WIFI_DIRECT_FOR_LAA_BOOL = "wifi.avoid_5ghz_wifi_direct_for_laa_bool";
@@ -13762,7 +13402,7 @@
}
public static interface CapabilityExchangeEventListener.OptionsRequestCallback {
- method public default void onRespondToCapabilityRequest(@NonNull android.telephony.ims.RcsContactUceCapability, boolean);
+ method public void onRespondToCapabilityRequest(@NonNull android.telephony.ims.RcsContactUceCapability, boolean);
method public void onRespondToCapabilityRequestWithError(@IntRange(from=100, to=699) int, @NonNull String);
}
@@ -14359,6 +13999,7 @@
public final class ContentCaptureContext implements android.os.Parcelable {
method @Nullable public android.content.ComponentName getActivityComponent();
+ method @Nullable public android.app.assist.ActivityId getActivityId();
method public int getDisplayId();
method public int getFlags();
method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 835c49f..1e5a6f1 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -5,6 +5,7 @@
field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
+ field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
@@ -30,6 +31,7 @@
field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
+ field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS";
field public static final String START_TASKS_FROM_RECENTS = "android.permission.START_TASKS_FROM_RECENTS";
@@ -397,6 +399,8 @@
method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int);
method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs();
method public void forceUpdateUserSetupComplete();
+ method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
+ method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
method public long getLastSecurityLogRetrievalTime();
@@ -542,6 +546,15 @@
}
+package android.app.assist {
+
+ public class ActivityId {
+ method public int getTaskId();
+ method @Nullable public android.os.IBinder getToken();
+ }
+
+}
+
package android.app.blob {
public class BlobStoreManager {
@@ -562,6 +575,16 @@
}
+package android.app.contentsuggestions {
+
+ public final class ContentSuggestionsManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS) public void resetTemporaryService(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS) public void setDefaultServiceEnabled(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS) public void setTemporaryService(int, @NonNull String, int);
+ }
+
+}
+
package android.app.prediction {
public final class AppPredictor {
@@ -695,6 +718,10 @@
field public int privateFlags;
}
+ public class CrossProfileApps {
+ method public boolean canConfigureInteractAcrossProfiles(@NonNull String);
+ }
+
public class LauncherApps {
ctor public LauncherApps(android.content.Context);
}
@@ -718,8 +745,10 @@
method public void holdLock(android.os.IBinder, int);
method @RequiresPermission(android.Manifest.permission.KEEP_UNINSTALLED_PACKAGES) public void setKeepUninstalledPackages(@NonNull java.util.List<java.lang.String>);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
+ field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
field public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
+ field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
@@ -746,6 +775,65 @@
ctor public ShortcutManager(android.content.Context);
}
+ public class UserInfo implements android.os.Parcelable {
+ ctor public UserInfo(int, String, int);
+ ctor public UserInfo(int, String, String, int);
+ ctor public UserInfo(int, String, String, int, String);
+ ctor @Deprecated public UserInfo();
+ ctor public UserInfo(android.content.pm.UserInfo);
+ method public boolean canHaveProfile();
+ method public int describeContents();
+ method public android.os.UserHandle getUserHandle();
+ method public boolean isAdmin();
+ method public boolean isDemo();
+ method public boolean isEnabled();
+ method public boolean isEphemeral();
+ method public boolean isFull();
+ method public boolean isGuest();
+ method public boolean isInitialized();
+ method public boolean isManagedProfile();
+ method public boolean isPrimary();
+ method public boolean isProfile();
+ method public boolean isQuietModeEnabled();
+ method public boolean isRestricted();
+ method public boolean isSystemOnly();
+ method public static boolean isSystemOnly(int);
+ method public boolean supportsSwitchTo();
+ method public boolean supportsSwitchToByUser();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.UserInfo> CREATOR;
+ field public static final int FLAG_ADMIN = 2; // 0x2
+ field @Deprecated public static final int FLAG_DEMO = 512; // 0x200
+ field public static final int FLAG_DISABLED = 64; // 0x40
+ field public static final int FLAG_EPHEMERAL = 256; // 0x100
+ field public static final int FLAG_FULL = 1024; // 0x400
+ field @Deprecated public static final int FLAG_GUEST = 4; // 0x4
+ field public static final int FLAG_INITIALIZED = 16; // 0x10
+ field @Deprecated public static final int FLAG_MANAGED_PROFILE = 32; // 0x20
+ field public static final int FLAG_PRIMARY = 1; // 0x1
+ field public static final int FLAG_PROFILE = 4096; // 0x1000
+ field public static final int FLAG_QUIET_MODE = 128; // 0x80
+ field @Deprecated public static final int FLAG_RESTRICTED = 8; // 0x8
+ field public static final int FLAG_SYSTEM = 2048; // 0x800
+ field public static final int NO_PROFILE_GROUP_ID = -10000; // 0xffffd8f0
+ field public boolean convertedFromPreCreated;
+ field public long creationTime;
+ field public int flags;
+ field public boolean guestToRemove;
+ field public String iconPath;
+ field public int id;
+ field public String lastLoggedInFingerprint;
+ field public long lastLoggedInTime;
+ field public String name;
+ field public boolean partial;
+ field public boolean preCreated;
+ field public int profileBadge;
+ field public int profileGroupId;
+ field public int restrictedProfileParentId;
+ field public int serialNumber;
+ field public String userType;
+ }
+
}
package android.content.res {
@@ -859,7 +947,7 @@
package android.graphics.fonts {
public class FontManager {
- method @Nullable public android.text.FontConfig getFontConfig();
+ method @NonNull public android.text.FontConfig getFontConfig();
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.graphics.fonts.FontFileUpdateRequest, @IntRange(from=0) int);
method @Deprecated @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int);
@@ -880,11 +968,21 @@
package android.hardware {
public final class SensorPrivacyManager {
- method public boolean isIndividualSensorPrivacyEnabled(int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setIndividualSensorPrivacy(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setIndividualSensorPrivacyForProfileGroup(int, boolean);
- field public static final int INDIVIDUAL_SENSOR_CAMERA = 2; // 0x2
- field public static final int INDIVIDUAL_SENSOR_MICROPHONE = 1; // 0x1
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(int);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(int, boolean);
+ }
+
+ public static interface SensorPrivacyManager.OnSensorPrivacyChangedListener {
+ method public void onSensorPrivacyChanged(boolean);
+ }
+
+ public static class SensorPrivacyManager.Sensors {
+ field public static final int CAMERA = 2; // 0x2
+ field public static final int MICROPHONE = 1; // 0x1
}
}
@@ -934,17 +1032,19 @@
package android.hardware.devicestate {
public final class DeviceStateManager {
- method public void addDeviceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
method @NonNull public int[] getSupportedStates();
- method public void removeDeviceStateListener(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
+ method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
+ method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0
}
- public static interface DeviceStateManager.DeviceStateListener {
- method public void onDeviceStateChanged(int);
+ public static interface DeviceStateManager.DeviceStateCallback {
+ method public default void onBaseStateChanged(int);
+ method public void onStateChanged(int);
+ method public default void onSupportedStatesChanged(@NonNull int[]);
}
public final class DeviceStateRequest {
@@ -1499,8 +1599,15 @@
}
public class UserManager {
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createProfileForUser(@Nullable String, @NonNull String, int, int, @Nullable String[]);
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String);
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public String getUserType();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
+ method public static boolean isGuestUserEphemeral();
method public static boolean isSplitSystemUser();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo preCreateUser(@NonNull String) throws android.os.UserManager.UserOperationException;
}
public final class VibrationAttributes implements android.os.Parcelable {
@@ -2480,6 +2587,9 @@
package android.view.contentcapture {
public final class ContentCaptureManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void resetTemporaryService(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void setDefaultServiceEnabled(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void setTemporaryService(int, @NonNull String, int);
field public static final String DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY = "idle_flush_frequency";
field public static final String DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL = "logging_level";
field public static final String DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE = "log_history_size";
@@ -2570,10 +2680,6 @@
method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
}
- public final class InputMethodInfo implements android.os.Parcelable {
- ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
- }
-
public final class InputMethodManager {
method public int getDisplayId();
method public boolean hasActiveInputConnection(@Nullable android.view.View);
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 87fb5b1..a536efb 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -468,7 +468,7 @@
GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
-
+
GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection<android.location.CorrelationVector>):
GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
@@ -480,7 +480,7 @@
GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
GetterSetterNames: android.location.GnssMeasurement#setSatellitePvt(android.location.SatellitePvt):
-
+
GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
GetterSetterNames: android.location.LocationRequest#isLocationSettingsIgnored():
@@ -953,6 +953,32 @@
MissingNullability: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context) parameter #0:
+MissingNullability: android.content.pm.UserInfo#UserInfo(android.content.pm.UserInfo) parameter #0:
+ Missing nullability on parameter `orig` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int) parameter #1:
+ Missing nullability on parameter `name` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int) parameter #2:
+ Missing nullability on parameter `iconPath` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #1:
+ Missing nullability on parameter `name` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #2:
+ Missing nullability on parameter `iconPath` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #4:
+ Missing nullability on parameter `userType` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, int) parameter #1:
+ Missing nullability on parameter `name` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#getUserHandle():
+ Missing nullability on method `getUserHandle` return
+MissingNullability: android.content.pm.UserInfo#iconPath:
+ Missing nullability on field `iconPath` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#lastLoggedInFingerprint:
+ Missing nullability on field `lastLoggedInFingerprint` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#name:
+ Missing nullability on field `name` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#userType:
+ Missing nullability on field `userType` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+ Missing nullability on parameter `dest` in method `writeToParcel`
MissingNullability: android.content.res.AssetManager#getOverlayablesToString(String) parameter #0:
MissingNullability: android.content.res.Configuration#windowConfiguration:
@@ -2433,6 +2459,38 @@
MutableBareField: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
+MutableBareField: android.content.pm.UserInfo#convertedFromPreCreated:
+ Bare field convertedFromPreCreated must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#creationTime:
+ Bare field creationTime must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#flags:
+ Bare field flags must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#guestToRemove:
+ Bare field guestToRemove must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#iconPath:
+ Bare field iconPath must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#id:
+ Bare field id must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#lastLoggedInFingerprint:
+ Bare field lastLoggedInFingerprint must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#lastLoggedInTime:
+ Bare field lastLoggedInTime must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#name:
+ Bare field name must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#partial:
+ Bare field partial must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#preCreated:
+ Bare field preCreated must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#profileBadge:
+ Bare field profileBadge must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#profileGroupId:
+ Bare field profileGroupId must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#restrictedProfileParentId:
+ Bare field restrictedProfileParentId must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#serialNumber:
+ Bare field serialNumber must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#userType:
+ Bare field userType must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#cache:
MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbName:
@@ -2548,15 +2606,15 @@
NoSettingsProvider: android.provider.Settings.Global#USE_OPEN_WIFI_PACKAGE:
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
-
+
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_CAPABILITY:
-
+
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE:
-
+
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_ALL:
-
+
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN:
-
+
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW:
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE:
@@ -2619,6 +2677,10 @@
+NullableCollection: android.os.UserManager#createProfileForUser(String, String, int, int, String[]) parameter #4:
+ Type of parameter disallowedPackages in android.os.UserManager.createProfileForUser(String name, String userType, int flags, int userId, String[] disallowedPackages) is a nullable collection (`java.lang.String[]`); must be non-null
+
+
OnNameExpected: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
OnNameExpected: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
@@ -2729,6 +2791,8 @@
ParcelNotFinal: android.app.WindowConfiguration:
+ParcelNotFinal: android.content.pm.UserInfo:
+ Parcelable classes must be final: android.content.pm.UserInfo is not final
ParcelNotFinal: android.net.metrics.IpConnectivityLog.Event:
ParcelNotFinal: android.os.IncidentManager.IncidentReport:
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a73fe71..f5f0b42 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -803,6 +803,7 @@
@UnsupportedAppUsage
private IBinder mToken;
private IBinder mAssistToken;
+ private IBinder mShareableActivityToken;
@UnsupportedAppUsage
private int mIdent;
@UnsupportedAppUsage
@@ -1210,7 +1211,7 @@
if (window != null) {
cm.updateWindowAttributes(window.getAttributes());
}
- cm.onActivityCreated(mToken, getComponentName());
+ cm.onActivityCreated(mToken, mShareableActivityToken, getComponentName());
break;
case CONTENT_CAPTURE_RESUME:
cm.onActivityResumed();
@@ -7118,6 +7119,9 @@
case "--contentcapture":
dumpContentCaptureManager(prefix, writer);
return;
+ case "--translation":
+ dumpUiTranslation(prefix, writer);
+ return;
}
}
writer.print(prefix); writer.print("Local Activity ");
@@ -7158,6 +7162,7 @@
dumpAutofillManager(prefix, writer);
dumpContentCaptureManager(prefix, writer);
+ dumpUiTranslation(prefix, writer);
ResourcesManager.getInstance().dump(prefix, writer);
}
@@ -7182,6 +7187,14 @@
}
}
+ void dumpUiTranslation(String prefix, PrintWriter writer) {
+ if (mUiTranslationController != null) {
+ mUiTranslationController.dump(prefix, writer);
+ } else {
+ writer.print(prefix); writer.println("No UiTranslationController");
+ }
+ }
+
/**
* Bit indicating that this activity is "immersive" and should not be
* interrupted by notifications if possible.
@@ -7838,7 +7851,8 @@
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
- Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
+ Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
+ IBinder shareableActivityToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
@@ -7860,6 +7874,7 @@
mInstrumentation = instr;
mToken = token;
mAssistToken = assistToken;
+ mShareableActivityToken = shareableActivityToken;
mIdent = ident;
mApplication = application;
mIntent = intent;
@@ -7918,6 +7933,11 @@
}
/** @hide */
+ public final IBinder getShareableActivityToken() {
+ return mParent != null ? mParent.getShareableActivityToken() : mShareableActivityToken;
+ }
+
+ /** @hide */
@VisibleForTesting
public final ActivityThread getActivityThread() {
return mMainThread;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c31c22c..c812e8e 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -30,6 +30,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.PowerWhitelistManager.TempAllowListType;
import android.os.TransactionTooLargeException;
import android.os.WorkSource;
@@ -102,12 +103,15 @@
* Sets how long a {@link PendingIntent} can be temporarily allowlisted to bypass restrictions
* such as Power Save mode.
* @param target
- * @param whitelistToken
+ * @param allowlistToken
* @param duration temp allowlist duration in milliseconds.
* @param type temp allowlist type defined at {@link TempAllowListType}
+ * @param reasonCode one of {@link ReasonCode}
+ * @param reason A human-readable reason for logging purposes.
*/
- public abstract void setPendingIntentWhitelistDuration(IIntentSender target,
- IBinder whitelistToken, long duration, int type);
+ public abstract void setPendingIntentAllowlistDuration(IIntentSender target,
+ IBinder allowlistToken, long duration, @TempAllowListType int type,
+ @ReasonCode int reasonCode, @Nullable String reason);
/**
* Returns the flags set for a {@link PendingIntent}.
@@ -127,20 +131,26 @@
IBinder allowlistToken);
/**
- * Allow DeviceIdleController to tell us about what apps are whitelisted.
+ * Allow DeviceIdleController to tell us about what apps are allowlisted.
*/
- public abstract void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids);
+ public abstract void setDeviceIdleAllowlist(int[] allAppids, int[] exceptIdleAppids);
/**
- * Update information about which app IDs are on the temp whitelist.
+ * Update information about which app IDs are on the temp allowlist.
* @param appids the updated list of appIds in temp allowlist.
* @param changingUid uid to add or remove to temp allowlist.
* @param adding true to add to temp allowlist, false to remove from temp allowlist.
* @param durationMs when adding is true, the duration to be in temp allowlist.
* @param type temp allowlist type defined at {@link TempAllowListType}.
+ * @param reasonCode one of {@link ReasonCode}
+ * @param reason A human-readable reason for logging purposes.
+ * @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
+ * is true.
*/
- public abstract void updateDeviceIdleTempWhitelist(int[] appids, int changingUid,
- boolean adding, long durationMs, @TempAllowListType int type);
+ public abstract void updateDeviceIdleTempAllowlist(int[] appids, int changingUid,
+ boolean adding, long durationMs, @TempAllowListType int type,
+ @ReasonCode int reasonCode,
+ @Nullable String reason, int callingUid);
/**
* Get the procstate for the UID. The return value will be between
@@ -335,10 +345,11 @@
* @param targetUid the UID that is been temp allowlisted.
* @param duration temp allowlist duration in milliseconds.
* @param type temp allowlist type defined at {@link TempAllowListType}
- * @param tag
+ * @param reasonCode one of {@link ReasonCode}
+ * @param reason
*/
- public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
- long duration, int type, String tag);
+ public abstract void tempAllowlistForPendingIntent(int callerPid, int callerUid, int targetUid,
+ long duration, int type, @ReasonCode int reasonCode, String reason);
public abstract int broadcastIntentInPackage(String packageName, @Nullable String featureId,
int uid, int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
@@ -495,9 +506,9 @@
/**
* Sends a broadcast, assuming the caller to be the system and allowing the inclusion of an
- * approved whitelist of app Ids >= {@link android.os.Process#FIRST_APPLICATION_UID} that the
+ * approved allowlist of app Ids >= {@link android.os.Process#FIRST_APPLICATION_UID} that the
* broadcast my be sent to; any app Ids < {@link android.os.Process#FIRST_APPLICATION_UID} are
- * automatically whitelisted.
+ * automatically allowlisted.
*
* @see com.android.server.am.ActivityManagerService#broadcastIntentWithFeature(
* IApplicationThread, String, Intent, String, IIntentReceiver, int, String, Bundle,
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 73cc13c8..a1dce77 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -320,6 +320,10 @@
private static final String KEY_OVERRIDE_TASK_TRANSITION =
"android:activity.overrideTaskTransition";
+ /** See {@link #setRemoveWithTaskOrganizer(boolean)}. */
+ private static final String KEY_REMOVE_WITH_TASK_ORGANIZER =
+ "android.activity.removeWithTaskOrganizer";
+
/**
* @see #setLaunchCookie
* @hide
@@ -405,6 +409,7 @@
private IRemoteTransition mRemoteTransition;
private boolean mOverrideTaskTransition;
private int mSplashScreenThemeResId;
+ private boolean mRemoveWithTaskOrganizer;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -1155,6 +1160,7 @@
KEY_REMOTE_TRANSITION));
mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
mSplashScreenThemeResId = opts.getInt(KEY_SPLASH_SCREEN_THEME);
+ mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
}
/**
@@ -1624,6 +1630,22 @@
}
/**
+ * Sets whether to remove the task when TaskOrganizer, which is managing it, is destroyed.
+ * @hide
+ */
+ public void setRemoveWithTaskOrganizer(boolean remove) {
+ mRemoveWithTaskOrganizer = remove;
+ }
+
+ /**
+ * @return whether to remove the task when TaskOrganizer, which is managing it, is destroyed.
+ * @hide
+ */
+ public boolean getRemoveWithTaskOranizer() {
+ return mRemoveWithTaskOrganizer;
+ }
+
+ /**
* Update the current values in this ActivityOptions from those supplied
* in <var>otherOptions</var>. Any values
* defined in <var>otherOptions</var> replace those in the base options.
@@ -1857,6 +1879,9 @@
if (mSplashScreenThemeResId != 0) {
b.putInt(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResId);
}
+ if (mRemoveWithTaskOrganizer) {
+ b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer);
+ }
return b;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 47d2e7c..730fce9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -517,6 +517,9 @@
@UnsupportedAppUsage
public IBinder token;
public IBinder assistToken;
+ // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
+ // used without security checks
+ public IBinder shareableActivityToken;
int ident;
@UnsupportedAppUsage
Intent intent;
@@ -604,9 +607,11 @@
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
- IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
+ IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
+ IBinder shareableActivityToken) {
this.token = token;
this.assistToken = assistToken;
+ this.shareableActivityToken = shareableActivityToken;
this.ident = ident;
this.intent = intent;
this.referrer = referrer;
@@ -3157,11 +3162,13 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public final Activity startActivityNow(Activity parent, String id,
- Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
- Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken) {
+ Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
+ Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken,
+ IBinder shareableActivityToken) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.assistToken = assistToken;
+ r.shareableActivityToken = shareableActivityToken;
r.ident = 0;
r.intent = intent;
r.state = state;
@@ -3504,7 +3511,7 @@
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
- r.assistToken);
+ r.assistToken, r.shareableActivityToken);
if (customIntent != null) {
activity.mIntent = customIntent;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 2f3b50b..160844a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1141,23 +1141,20 @@
*
* @hide
*/
- // TODO: Add as AppProtoEnums
- public static final int OP_PHONE_CALL_MICROPHONE = 100;
+ public static final int OP_PHONE_CALL_MICROPHONE = AppProtoEnums.APP_OP_PHONE_CALL_MICROPHONE;
/**
* Phone call is using camera
*
* @hide
*/
- // TODO: Add as AppProtoEnums
- public static final int OP_PHONE_CALL_CAMERA = 101;
+ public static final int OP_PHONE_CALL_CAMERA = AppProtoEnums.APP_OP_PHONE_CALL_CAMERA;
/**
* Audio is being recorded for hotword detection.
*
* @hide
*/
- // TODO: Add as AppProtoEnums
- public static final int OP_RECORD_AUDIO_HOTWORD = 102;
+ public static final int OP_RECORD_AUDIO_HOTWORD = AppProtoEnums.APP_OP_RECORD_AUDIO_HOTWORD;
/**
* Manage credentials in the system KeyChain.
@@ -1184,10 +1181,29 @@
*/
public static final int OP_SCHEDULE_EXACT_ALARM = AppProtoEnums.APP_OP_SCHEDULE_EXACT_ALARM;
+ /**
+ * Fine location being accessed by a location source, which is
+ * a component that already has location data since it is the one
+ * that produces location, which is it is a data source for
+ * location data.
+ *
+ * @hide
+ */
+ public static final int OP_FINE_LOCATION_SOURCE = AppProtoEnums.APP_OP_FINE_LOCATION_SOURCE;
+
+ /**
+ * Coarse location being accessed by a location source, which is
+ * a component that already has location data since it is the one
+ * that produces location, which is it is a data source for
+ * location data.
+ *
+ * @hide
+ */
+ public static final int OP_COARSE_LOCATION_SOURCE = AppProtoEnums.APP_OP_COARSE_LOCATION_SOURCE;
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 108;
+ public static final int _NUM_OP = 110;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1567,6 +1583,24 @@
*/
public static final String OPSTR_SCHEDULE_EXACT_ALARM = "android:schedule_exact_alarm";
+ /**
+ * Fine location being accessed by a location source, which is
+ * a component that already has location since it is the one that
+ * produces location.
+ *
+ * @hide
+ */
+ public static final String OPSTR_FINE_LOCATION_SOURCE = "android:fine_location_source";
+
+ /**
+ * Coarse location being accessed by a location source, which is
+ * a component that already has location since it is the one that
+ * produces location.
+ *
+ * @hide
+ */
+ public static final String OPSTR_COARSE_LOCATION_SOURCE = "android:coarse_location_source";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1767,6 +1801,8 @@
OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
OP_RECORD_AUDIO_OUTPUT, // RECORD_AUDIO_OUTPUT
OP_SCHEDULE_EXACT_ALARM, // SCHEDULE_EXACT_ALARM
+ OP_FINE_LOCATION, // OP_FINE_LOCATION_SOURCE
+ OP_COARSE_LOCATION, // OP_COARSE_LOCATION_SOURCE
};
/**
@@ -1881,6 +1917,8 @@
OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
OPSTR_RECORD_AUDIO_OUTPUT,
OPSTR_SCHEDULE_EXACT_ALARM,
+ OPSTR_FINE_LOCATION_SOURCE,
+ OPSTR_COARSE_LOCATION_SOURCE,
};
/**
@@ -1996,6 +2034,8 @@
"USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER",
"RECORD_AUDIO_OUTPUT",
"SCHEDULE_EXACT_ALARM",
+ "FINE_LOCATION_SOURCE",
+ "COARSE_LOCATION_SOURCE",
};
/**
@@ -2112,6 +2152,8 @@
Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
null, // no permission for OP_RECORD_AUDIO_OUTPUT
Manifest.permission.SCHEDULE_EXACT_ALARM,
+ null, // no permission for OP_ACCESS_FINE_LOCATION_SOURCE,
+ null, // no permission for OP_ACCESS_COARSE_LOCATION_SOURCE,
};
/**
@@ -2228,6 +2270,8 @@
null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
null, // RECORD_AUDIO_OUTPUT
null, // SCHEDULE_EXACT_ALARM
+ null, // ACCESS_FINE_LOCATION_SOURCE
+ null, // ACCESS_COARSE_LOCATION_SOURCE
};
/**
@@ -2343,6 +2387,8 @@
null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
null, // RECORD_AUDIO_OUTPUT
null, // SCHEDULE_EXACT_ALARM
+ null, // ACCESS_FINE_LOCATION_SOURCE
+ null, // ACCESS_COARSE_LOCATION_SOURCE
};
/**
@@ -2457,6 +2503,8 @@
AppOpsManager.MODE_DEFAULT, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO_OUTPUT
AppOpsManager.MODE_DEFAULT, // SCHEDULE_EXACT_ALARM
+ AppOpsManager.MODE_ALLOWED, // ACCESS_FINE_LOCATION_SOURCE
+ AppOpsManager.MODE_ALLOWED, // ACCESS_COARSE_LOCATION_SOURCE
};
/**
@@ -2575,6 +2623,8 @@
true, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
false, // RECORD_AUDIO_OUTPUT
false, // SCHEDULE_EXACT_ALARM
+ false, // ACCESS_FINE_LOCATION_SOURCE
+ false, // ACCESS_COARSE_LOCATION_SOURCE
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 062cab4..a6260d6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1797,6 +1797,7 @@
}
}
+ @UnsupportedAppUsage
protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) {
mContext = context;
mPM = pm;
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 445fdd8..477e96b 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,11 +16,13 @@
package android.app;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerWhitelistManager;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.PowerWhitelistManager.TempAllowListType;
/**
@@ -31,8 +33,11 @@
*/
@SystemApi
public class BroadcastOptions {
- private long mTemporaryAppWhitelistDuration;
- private @TempAllowListType int mTemporaryAppWhitelistType;
+ private long mTemporaryAppAllowlistDuration;
+ private @TempAllowListType int mTemporaryAppAllowlistType;
+ private @ReasonCode int mTemporaryAppAllowlistReasonCode =
+ PowerWhitelistManager.REASON_UNKNOWN;
+ private @Nullable String mTemporaryAppAllowlistReason;
private int mMinManifestReceiverApiLevel = 0;
private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
private boolean mDontSendToRestrictedApps = false;
@@ -42,11 +47,17 @@
* How long to temporarily put an app on the power allowlist when executing this broadcast
* to it.
*/
- static final String KEY_TEMPORARY_APP_WHITELIST_DURATION
- = "android:broadcast.temporaryAppWhitelistDuration";
+ static final String KEY_TEMPORARY_APP_ALLOWLIST_DURATION
+ = "android:broadcast.temporaryAppAllowlistDuration";
- static final String KEY_TEMPORARY_APP_WHITELIST_TYPE
- = "android:broadcast.temporaryAppWhitelistType";
+ static final String KEY_TEMPORARY_APP_ALLOWLIST_TYPE
+ = "android:broadcast.temporaryAppAllowlistType";
+
+ static final String KEY_TEMPORARY_APP_ALLOWLIST_REASON_CODE =
+ "android:broadcast.temporaryAppAllowlistReasonCode";
+
+ static final String KEY_TEMPORARY_APP_ALLOWLIST_REASON =
+ "android:broadcast.temporaryAppAllowlistReason";
/**
* Corresponds to {@link #setMinManifestReceiverApiLevel}.
@@ -80,6 +91,7 @@
@Deprecated
public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED =
PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
/**
* @hide
* @deprecated Use {@link android.os.PowerWhitelistManager#
@@ -99,8 +111,11 @@
/** @hide */
public BroadcastOptions(Bundle opts) {
- mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION);
- mTemporaryAppWhitelistType = opts.getInt(KEY_TEMPORARY_APP_WHITELIST_TYPE);
+ mTemporaryAppAllowlistDuration = opts.getLong(KEY_TEMPORARY_APP_ALLOWLIST_DURATION);
+ mTemporaryAppAllowlistType = opts.getInt(KEY_TEMPORARY_APP_ALLOWLIST_TYPE);
+ mTemporaryAppAllowlistReasonCode = opts.getInt(KEY_TEMPORARY_APP_ALLOWLIST_REASON_CODE,
+ PowerWhitelistManager.REASON_UNKNOWN);
+ mTemporaryAppAllowlistReason = opts.getString(KEY_TEMPORARY_APP_ALLOWLIST_REASON);
mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0);
mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL,
Build.VERSION_CODES.CUR_DEVELOPMENT);
@@ -113,45 +128,70 @@
* Set a duration for which the system should temporary place an application on the
* power allowlist when this broadcast is being delivered to it.
* @param duration The duration in milliseconds; 0 means to not place on allowlist.
+ * @deprecated use {@link #setTemporaryAppAllowlist(long, int, int, String)} instead.
*/
+ @Deprecated
@RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
public void setTemporaryAppWhitelistDuration(long duration) {
- mTemporaryAppWhitelistDuration = duration;
- mTemporaryAppWhitelistType =
- PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+ setTemporaryAppAllowlist(duration,
+ PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ PowerWhitelistManager.REASON_UNKNOWN, null);
}
/**
* Set a duration for which the system should temporary place an application on the
* power allowlist when this broadcast is being delivered to it, specify the temp allowlist
* type.
- * @param type one of {@link TempAllowListType}
* @param duration the duration in milliseconds; 0 means to not place on allowlist.
+ * @param type one of {@link TempAllowListType}
+ * @param reasonCode one of {@link ReasonCode}, use
+ * {@link PowerWhitelistManager#REASON_UNKNOWN} if not sure.
+ * @param reason A human-readable reason explaining why the app is temp allowlisted. Only
+ * used for logging purposes. Could be null or empty string.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
- public void setTemporaryAppWhitelistDuration(@TempAllowListType int type, long duration) {
- mTemporaryAppWhitelistDuration = duration;
- mTemporaryAppWhitelistType = type;
+ public void setTemporaryAppAllowlist(long duration, @TempAllowListType int type,
+ @ReasonCode int reasonCode, @Nullable String reason) {
+ mTemporaryAppAllowlistDuration = duration;
+ mTemporaryAppAllowlistType = type;
+ mTemporaryAppAllowlistReasonCode = reasonCode;
+ mTemporaryAppAllowlistReason = reason;
}
/**
- * Return {@link #setTemporaryAppWhitelistDuration}.
+ * Return {@link #setTemporaryAppAllowlist}.
* @hide
*/
- public long getTemporaryAppWhitelistDuration() {
- return mTemporaryAppWhitelistDuration;
+ public long getTemporaryAppAllowlistDuration() {
+ return mTemporaryAppAllowlistDuration;
}
/**
- * Return {@link #mTemporaryAppWhitelistType}.
+ * Return {@link #mTemporaryAppAllowlistType}.
* @hide
*/
- public @TempAllowListType int getTemporaryAppWhitelistType() {
- return mTemporaryAppWhitelistType;
+ public @TempAllowListType int getTemporaryAppAllowlistType() {
+ return mTemporaryAppAllowlistType;
+ }
+
+ /**
+ * Return {@link #mTemporaryAppAllowlistReasonCode}.
+ * @hide
+ */
+ public @ReasonCode int getTemporaryAppAllowlistReasonCode() {
+ return mTemporaryAppAllowlistReasonCode;
+ }
+
+ /**
+ * Return {@link #mTemporaryAppAllowlistReason}.
+ * @hide
+ */
+ public @Nullable String getTemporaryAppAllowlistReason() {
+ return mTemporaryAppAllowlistReason;
}
/**
@@ -236,11 +276,17 @@
*/
public Bundle toBundle() {
Bundle b = new Bundle();
- if (mTemporaryAppWhitelistDuration > 0) {
- b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration);
+ if (mTemporaryAppAllowlistDuration > 0) {
+ b.putLong(KEY_TEMPORARY_APP_ALLOWLIST_DURATION, mTemporaryAppAllowlistDuration);
}
- if (mTemporaryAppWhitelistType != 0) {
- b.putInt(KEY_TEMPORARY_APP_WHITELIST_TYPE, mTemporaryAppWhitelistType);
+ if (mTemporaryAppAllowlistType != 0) {
+ b.putInt(KEY_TEMPORARY_APP_ALLOWLIST_TYPE, mTemporaryAppAllowlistType);
+ }
+ if (mTemporaryAppAllowlistReasonCode != PowerWhitelistManager.REASON_UNKNOWN) {
+ b.putInt(KEY_TEMPORARY_APP_ALLOWLIST_REASON_CODE, mTemporaryAppAllowlistReasonCode);
+ }
+ if (mTemporaryAppAllowlistReason != null) {
+ b.putString(KEY_TEMPORARY_APP_ALLOWLIST_REASON, mTemporaryAppAllowlistReason);
}
if (mMinManifestReceiverApiLevel != 0) {
b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 2e684b1..3a8172e 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -549,7 +549,7 @@
/**
* Add a bare uid to the background restrictions whitelist. Only the system uid may call this.
*/
- void backgroundWhitelistUid(int uid);
+ void backgroundAllowlistUid(int uid);
// Start of P transactions
/**
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 8d1076e..b2184fe 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1247,7 +1247,8 @@
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
- null /* window */, null /* activityConfigCallback */, null /*assistToken*/);
+ null /* window */, null /* activityConfigCallback */, null /*assistToken*/,
+ null /*shareableActivityToken*/);
return activity;
}
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 74e6125..6b5f19a 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -158,7 +158,7 @@
r.activityInfo = mActivityThread.resolveActivityInfo(r.intent);
}
r.activity = mActivityThread.startActivityNow(
- mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance, r);
+ mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance, r, r);
if (r.activity == null) {
return;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f7304fb..8167622 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5013,6 +5013,7 @@
bindNotificationHeader(contentView, p);
bindLargeIconAndApplyMargin(contentView, p, result);
boolean showProgress = handleProgressBar(contentView, ex, p);
+ boolean hasSecondLine = showProgress;
if (p.hasTitle()) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
contentView.setTextViewText(R.id.title, processTextSpans(p.title));
@@ -5028,11 +5029,27 @@
contentView.setTextViewText(textId, processTextSpans(p.text));
setTextViewColorSecondary(contentView, textId, p);
contentView.setViewVisibility(textId, View.VISIBLE);
+ hasSecondLine = true;
}
+ setHeaderlessVerticalMargins(contentView, p, hasSecondLine);
return contentView;
}
+ private static void setHeaderlessVerticalMargins(RemoteViews contentView,
+ StandardTemplateParams p, boolean hasSecondLine) {
+ if (!p.mHeaderless) {
+ return;
+ }
+ int marginDimen = hasSecondLine
+ ? R.dimen.notification_headerless_margin_twoline
+ : R.dimen.notification_headerless_margin_oneline;
+ contentView.setViewLayoutMarginDimen(R.id.notification_headerless_view_column,
+ RemoteViews.MARGIN_TOP, marginDimen);
+ contentView.setViewLayoutMarginDimen(R.id.notification_headerless_view_column,
+ RemoteViews.MARGIN_BOTTOM, marginDimen);
+ }
+
private CharSequence processTextSpans(CharSequence text) {
if (hasForegroundColor() || mInNightMode) {
return ContrastColorUtil.clearColorSpans(text);
@@ -5494,12 +5511,28 @@
big.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE);
big.setTextViewText(R.id.notification_material_reply_text_3, null);
- final boolean snoozeEnabled = mContext.getContentResolver() != null
- && (Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1);
- int bottomMarginDimen = snoozeEnabled ? 0 : R.dimen.notification_content_margin;
+ // This may get erased by bindSnoozeAction
big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
- RemoteViews.MARGIN_BOTTOM, bottomMarginDimen);
+ RemoteViews.MARGIN_BOTTOM, R.dimen.notification_content_margin);
+ }
+
+ private void bindSnoozeAction(RemoteViews big, StandardTemplateParams p) {
+ boolean hideSnoozeButton = mN.isForegroundService() || mN.fullScreenIntent != null
+ || isColorized(p) || p.mViewType == StandardTemplateParams.VIEW_TYPE_HEADS_UP;
+ big.setBoolean(R.id.snooze_button, "setEnabled", !hideSnoozeButton);
+ if (hideSnoozeButton) {
+ // Only hide; NotificationContentView will show it when it adds the click listener
+ big.setViewVisibility(R.id.snooze_button, View.GONE);
+ }
+
+ final boolean snoozeEnabled = !hideSnoozeButton
+ && mContext.getContentResolver() != null
+ && (Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1);
+ if (snoozeEnabled) {
+ big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
+ RemoteViews.MARGIN_BOTTOM, 0);
+ }
}
/**
@@ -5521,6 +5554,7 @@
RemoteViews big = applyStandardTemplate(layoutId, p, result);
resetStandardTemplateWithActions(big);
+ bindSnoozeAction(big, p);
boolean validRemoteInput = false;
@@ -6834,26 +6868,13 @@
if (decorationType <= DevFlags.DECORATION_PARTIAL) {
template.removeFromParent(R.id.notification_top_line);
}
- if (decorationType != DevFlags.DECORATION_FULL_COMPATIBLE) {
- // Change the max content size from 60dp (the compatible size) to 48dp
- // (the constrained size). This is done by increasing the minimum margin
- // (implemented as top/bottom margins) and decreasing the extra margin
- // (implemented as the height of shrinkable top/bottom views in the column).
- template.setViewLayoutMarginDimen(
- R.id.notification_headerless_view_column,
- RemoteViews.MARGIN_TOP,
- R.dimen.notification_headerless_margin_constrained_minimum);
- template.setViewLayoutMarginDimen(
- R.id.notification_headerless_view_column,
- RemoteViews.MARGIN_BOTTOM,
- R.dimen.notification_headerless_margin_constrained_minimum);
- template.setViewLayoutHeightDimen(
- R.id.notification_headerless_margin_extra_top,
- R.dimen.notification_headerless_margin_constrained_extra);
- template.setViewLayoutHeightDimen(
- R.id.notification_headerless_margin_extra_bottom,
- R.dimen.notification_headerless_margin_constrained_extra);
- }
+ // The vertical margins are bigger in the "two-line" scenario than the "one-line"
+ // scenario, but the 'compatible' decoration state is intended to have 3 lines,
+ // (1 for the top line views and 2 for the custom views), so in that one case we
+ // use the smaller 1-line margins. This gives the compatible case 88-16*2=56 dp of
+ // height, 24dp of which goes to the top line, leaving 32dp for the custom view.
+ boolean hasSecondLine = decorationType != DevFlags.DECORATION_FULL_COMPATIBLE;
+ Builder.setHeaderlessVerticalMargins(template, p, hasSecondLine);
} else {
// also update the end margin to account for the large icon or expander
Resources resources = context.getResources();
@@ -9358,6 +9379,7 @@
// Bind actions.
mBuilder.resetStandardTemplateWithActions(contentView);
+ mBuilder.bindSnoozeAction(contentView, p);
bindCallActions(contentView, p);
// Bind some extra conversation-specific header fields.
@@ -9417,11 +9439,16 @@
}
private void bindCallerVerification(RemoteViews contentView, StandardTemplateParams p) {
+ String iconContentDescription = null;
+ boolean showDivider = true;
if (mVerificationIcon != null) {
contentView.setImageViewIcon(R.id.verification_icon, mVerificationIcon);
contentView.setDrawableTint(R.id.verification_icon, false /* targetBackground */,
mBuilder.getSecondaryTextColor(p), PorterDuff.Mode.SRC_ATOP);
contentView.setViewVisibility(R.id.verification_icon, View.VISIBLE);
+ iconContentDescription = mBuilder.mContext.getString(
+ R.string.notification_verified_content_description);
+ showDivider = false; // the icon replaces the divider
} else {
contentView.setViewVisibility(R.id.verification_icon, View.GONE);
}
@@ -9429,8 +9456,17 @@
contentView.setTextViewText(R.id.verification_text, mVerificationText);
mBuilder.setTextViewColorSecondary(contentView, R.id.verification_text, p);
contentView.setViewVisibility(R.id.verification_text, View.VISIBLE);
+ iconContentDescription = null; // let the app's text take precedence
} else {
contentView.setViewVisibility(R.id.verification_text, View.GONE);
+ showDivider = false; // no divider if no text
+ }
+ contentView.setContentDescription(R.id.verification_icon, iconContentDescription);
+ if (showDivider) {
+ contentView.setViewVisibility(R.id.verification_divider, View.VISIBLE);
+ mBuilder.setTextViewColorSecondary(contentView, R.id.verification_divider, p);
+ } else {
+ contentView.setViewVisibility(R.id.verification_divider, View.GONE);
}
}
@@ -11998,6 +12034,7 @@
boolean mHideTitle;
boolean mHideActions;
boolean mHideProgress;
+ boolean mHideSnoozeButton;
boolean mPromotePicture;
boolean mAllowActionIcons;
CharSequence title;
@@ -12015,6 +12052,7 @@
mHideTitle = false;
mHideActions = false;
mHideProgress = false;
+ mHideSnoozeButton = false;
mPromotePicture = false;
mAllowActionIcons = false;
title = null;
@@ -12061,6 +12099,11 @@
return this;
}
+ final StandardTemplateParams hideSnoozeButton(boolean hideSnoozeButton) {
+ this.mHideSnoozeButton = hideSnoozeButton;
+ return this;
+ }
+
final StandardTemplateParams promotePicture(boolean promotePicture) {
this.mPromotePicture = promotePicture;
return this;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 2f06bdc..549bd4b 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -61,6 +61,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Objects;
/**
* A description of an Intent and target action to perform with it. Instances
@@ -464,8 +465,7 @@
public static PendingIntent getActivityAsUser(Context context, int requestCode,
@NonNull Intent intent, int flags, Bundle options, UserHandle user) {
String packageName = context.getPackageName();
- String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
- context.getContentResolver()) : null;
+ String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
@@ -639,7 +639,7 @@
*/
@SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public static PendingIntent getBroadcast(Context context, int requestCode,
- Intent intent, @Flags int flags) {
+ @NonNull Intent intent, @Flags int flags) {
return getBroadcastAsUser(context, requestCode, intent, flags, context.getUser());
}
@@ -652,8 +652,7 @@
public static PendingIntent getBroadcastAsUser(Context context, int requestCode,
Intent intent, int flags, UserHandle userHandle) {
String packageName = context.getPackageName();
- String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
- context.getContentResolver()) : null;
+ String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
@@ -732,8 +731,7 @@
private static PendingIntent buildServicePendingIntent(Context context, int requestCode,
Intent intent, int flags, int serviceKind) {
String packageName = context.getPackageName();
- String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
- context.getContentResolver()) : null;
+ String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
@@ -755,6 +753,7 @@
* @return Returns a IntentSender object that wraps the sender of PendingIntent
*
*/
+ @NonNull
public IntentSender getIntentSender() {
return new IntentSender(mTarget, mWhitelistToken);
}
@@ -767,6 +766,7 @@
try {
ActivityManager.getService().cancelIntentSender(mTarget);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -1009,6 +1009,7 @@
* @deprecated Renamed to {@link #getCreatorPackage()}.
*/
@Deprecated
+ @NonNull
public String getTargetPackage() {
return getCreatorPackage();
}
@@ -1028,10 +1029,9 @@
* only use this information to identify who you expect to be interacting with
* through a {@link #send} call, not who gave you the PendingIntent.</p>
*
- * @return The package name of the PendingIntent, or null if there is
- * none associated with it.
+ * @return The package name of the PendingIntent.
*/
- @Nullable
+ @NonNull
public String getCreatorPackage() {
return getCachedInfo().getCreatorPackage();
}
@@ -1143,13 +1143,12 @@
* only use this information to identify who you expect to be interacting with
* through a {@link #send} call, not who gave you the PendingIntent.</p>
*
- * @return The user handle of the PendingIntent, or null if there is
- * none associated with it.
+ * @return The user handle of the PendingIntent
*/
- @Nullable
+ @NonNull
public UserHandle getCreatorUserHandle() {
int uid = getCachedInfo().getCreatorUid();
- return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
+ return UserHandle.getUserHandleForUid(uid);
}
/**
@@ -1282,7 +1281,7 @@
sb.append("PendingIntent{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(": ");
- sb.append(mTarget != null ? mTarget.asBinder() : null);
+ sb.append(mTarget.asBinder());
sb.append('}');
return sb.toString();
}
@@ -1290,9 +1289,7 @@
/** @hide */
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- if (mTarget != null) {
- proto.write(PendingIntentProto.TARGET, mTarget.asBinder().toString());
- }
+ proto.write(PendingIntentProto.TARGET, mTarget.asBinder().toString());
proto.end(token);
}
@@ -1309,8 +1306,7 @@
}
- public static final @android.annotation.NonNull Parcelable.Creator<PendingIntent> CREATOR
- = new Parcelable.Creator<PendingIntent>() {
+ public static final @NonNull Creator<PendingIntent> CREATOR = new Creator<PendingIntent>() {
public PendingIntent createFromParcel(Parcel in) {
IBinder target = in.readStrongBinder();
return target != null
@@ -1364,11 +1360,11 @@
* @hide
*/
public PendingIntent(IIntentSender target) {
- mTarget = target;
+ mTarget = Objects.requireNonNull(target);
}
/*package*/ PendingIntent(IBinder target, Object cookie) {
- mTarget = IIntentSender.Stub.asInterface(target);
+ mTarget = Objects.requireNonNull(IIntentSender.Stub.asInterface(target));
if (cookie != null) {
mWhitelistToken = (IBinder)cookie;
}
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 3abba43..0a8a734 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -16,9 +16,9 @@
package android.app;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -35,6 +35,8 @@
import com.android.internal.util.ContrastColorUtil;
import java.io.FileOutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -50,6 +52,13 @@
* or {@link WallpaperColors#getTertiaryColor()}.
*/
public final class WallpaperColors implements Parcelable {
+ /**
+ * @hide
+ */
+ @IntDef(prefix = "HINT_", value = {HINT_SUPPORTS_DARK_TEXT, HINT_SUPPORTS_DARK_THEME},
+ flag = true)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ColorsHints {}
private static final boolean DEBUG_DARK_PIXELS = false;
@@ -57,18 +66,14 @@
* Specifies that dark text is preferred over the current wallpaper for best presentation.
* <p>
* eg. A launcher may set its text color to black if this flag is specified.
- * @hide
*/
- @SystemApi
public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
/**
* Specifies that dark theme is preferred over the current wallpaper for best presentation.
* <p>
* eg. A launcher may set its drawer color to black if this flag is specified.
- * @hide
*/
- @SystemApi
public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
/**
@@ -229,15 +234,12 @@
* @param primaryColor Primary color.
* @param secondaryColor Secondary color.
* @param tertiaryColor Tertiary color.
- * @param colorHints A combination of WallpaperColor hints.
- * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
+ * @param colorHints A combination of color hints.
* @see WallpaperColors#fromBitmap(Bitmap)
* @see WallpaperColors#fromDrawable(Drawable)
- * @hide
*/
- @SystemApi
public WallpaperColors(@NonNull Color primaryColor, @Nullable Color secondaryColor,
- @Nullable Color tertiaryColor, int colorHints) {
+ @Nullable Color tertiaryColor, @ColorsHints int colorHints) {
if (primaryColor == null) {
throw new IllegalArgumentException("Primary color should never be null.");
@@ -268,13 +270,14 @@
*
* @param populationByColor Map with keys of colors, and value representing the number of
* occurrences of color in the wallpaper.
- * @param colorHints A combination of WallpaperColor hints.
+ * @param colorHints A combination of color hints.
* @hide
* @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
* @see WallpaperColors#fromBitmap(Bitmap)
* @see WallpaperColors#fromDrawable(Drawable)
*/
- public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor, int colorHints) {
+ public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor,
+ @ColorsHints int colorHints) {
mAllColors = populationByColor;
ArrayList<Map.Entry<Integer, Integer>> mapEntries = new ArrayList(
@@ -386,27 +389,14 @@
}
/**
- * Combination of WallpaperColor hints.
- *
- * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
- * @return True if dark text is supported.
- * @hide
+ * Returns the color hints for this instance.
+ * @return The color hints.
*/
- @SystemApi
- public int getColorHints() {
+ public @ColorsHints int getColorHints() {
return mColorHints;
}
/**
- * @param colorHints Combination of WallpaperColors hints.
- * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
- * @hide
- */
- public void setColorHints(int colorHints) {
- mColorHints = colorHints;
- }
-
- /**
* Checks if image is bright and clean enough to support light text.
*
* @param source What to read.
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 4ae1670..d04ca1d9 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -57,7 +57,7 @@
* TODO: Investigate combining with {@link #mAppBounds}. Can the latter be a product of the
* former?
*/
- private Rect mBounds = new Rect();
+ private final Rect mBounds = new Rect();
/**
* {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
@@ -71,7 +71,7 @@
* The maximum {@link Rect} bounds that an app can expect. It is used to report value of
* {@link WindowManager#getMaximumWindowMetrics()}.
*/
- private Rect mMaxBounds = new Rect();
+ private final Rect mMaxBounds = new Rect();
/**
* The current rotation of this window container relative to the default
@@ -240,9 +240,9 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mBounds, flags);
- dest.writeParcelable(mAppBounds, flags);
- dest.writeParcelable(mMaxBounds, flags);
+ mBounds.writeToParcel(dest, flags);
+ dest.writeTypedObject(mAppBounds, flags);
+ mMaxBounds.writeToParcel(dest, flags);
dest.writeInt(mWindowingMode);
dest.writeInt(mActivityType);
dest.writeInt(mAlwaysOnTop);
@@ -250,10 +250,11 @@
dest.writeInt(mDisplayWindowingMode);
}
- private void readFromParcel(Parcel source) {
- mBounds = source.readParcelable(Rect.class.getClassLoader());
- mAppBounds = source.readParcelable(Rect.class.getClassLoader());
- mMaxBounds = source.readParcelable(Rect.class.getClassLoader());
+ /** @hide */
+ public void readFromParcel(@NonNull Parcel source) {
+ mBounds.readFromParcel(source);
+ mAppBounds = source.readTypedObject(Rect.CREATOR);
+ mMaxBounds.readFromParcel(source);
mWindowingMode = source.readInt();
mActivityType = source.readInt();
mAlwaysOnTop = source.readInt();
@@ -693,9 +694,7 @@
}
protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
- if (mBounds != null) {
- mBounds.dumpDebug(protoOutputStream, BOUNDS);
- }
+ mBounds.dumpDebug(protoOutputStream, BOUNDS);
mMaxBounds.dumpDebug(protoOutputStream, MAX_BOUNDS);
protoOutputStream.end(token);
}
@@ -719,11 +718,9 @@
mAppBounds.readFromProto(proto, APP_BOUNDS);
break;
case (int) BOUNDS:
- mBounds = new Rect();
mBounds.readFromProto(proto, BOUNDS);
break;
case (int) MAX_BOUNDS:
- mMaxBounds = new Rect();
mMaxBounds.readFromProto(proto, MAX_BOUNDS);
break;
case (int) WINDOWING_MODE:
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 721a444..cccc929 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -585,6 +585,9 @@
* @param intent The received intent as per {@link #onReceive}.
*/
public void onEnabled(@NonNull Context context, @NonNull Intent intent) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onEnabled() on user " + context.getUserId());
+ }
}
/**
@@ -600,6 +603,10 @@
*/
public @Nullable CharSequence onDisableRequested(@NonNull Context context,
@NonNull Intent intent) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onDisableRequested() on user "
+ + context.getUserId());
+ }
return null;
}
@@ -612,6 +619,9 @@
* @param intent The received intent as per {@link #onReceive}.
*/
public void onDisabled(@NonNull Context context, @NonNull Intent intent) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onDisabled() on user " + context.getUserId());
+ }
}
/**
@@ -786,6 +796,10 @@
* @param intent The received intent as per {@link #onReceive}.
*/
public void onProfileProvisioningComplete(@NonNull Context context, @NonNull Intent intent) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onProfileProvisioningComplete() on user "
+ + context.getUserId());
+ }
}
/**
@@ -961,6 +975,9 @@
*/
public void onUserAdded(@NonNull Context context, @NonNull Intent intent,
@NonNull UserHandle addedUser) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onUserAdded() on user " + context.getUserId());
+ }
}
/**
@@ -974,6 +991,9 @@
*/
public void onUserRemoved(@NonNull Context context, @NonNull Intent intent,
@NonNull UserHandle removedUser) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onUserRemoved() on user " + context.getUserId());
+ }
}
/**
@@ -987,6 +1007,9 @@
*/
public void onUserStarted(@NonNull Context context, @NonNull Intent intent,
@NonNull UserHandle startedUser) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onUserStarted() on user " + context.getUserId());
+ }
}
/**
@@ -1000,6 +1023,9 @@
*/
public void onUserStopped(@NonNull Context context, @NonNull Intent intent,
@NonNull UserHandle stoppedUser) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onUserStopped() on user " + context.getUserId());
+ }
}
/**
@@ -1013,6 +1039,9 @@
*/
public void onUserSwitched(@NonNull Context context, @NonNull Intent intent,
@NonNull UserHandle switchedUser) {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, getClass().getName() + ".onUserSwitched() on user " + context.getUserId());
+ }
}
/**
@@ -1104,7 +1133,8 @@
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
String action = intent.getAction();
if (LOCAL_LOGV) {
- Log.v(TAG, "onReceive(): received " + action + " on user " + context.getUserId());
+ Log.v(TAG, getClass().getName() + ".onReceive(): received " + action + " on user "
+ + context.getUserId());
}
if (ACTION_PASSWORD_CHANGED.equals(action)) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bb1ff60..b919bfc 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -12239,8 +12239,9 @@
*
* @hide
*/
- public Set<String> getDisallowedSystemApps(ComponentName admin, int userId,
- String provisioningAction) {
+ @TestApi
+ public @NonNull Set<String> getDisallowedSystemApps(@NonNull ComponentName admin,
+ @UserIdInt int userId, @NonNull String provisioningAction) {
try {
return new ArraySet<>(
mService.getDisallowedSystemApps(admin, userId, provisioningAction));
@@ -13004,6 +13005,7 @@
*
* @hide
*/
+ @TestApi
public @NonNull Set<String> getDefaultCrossProfilePackages() {
throwIfParentInstance("getDefaultCrossProfilePackages");
if (mService != null) {
diff --git a/core/java/android/app/assist/ActivityId.java b/core/java/android/app/assist/ActivityId.java
new file mode 100644
index 0000000..fb0d056
--- /dev/null
+++ b/core/java/android/app/assist/ActivityId.java
@@ -0,0 +1,125 @@
+/*
+ * 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.assist;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.service.contentcapture.ContentCaptureService;
+import android.view.contentcapture.ContentCaptureContext;
+import android.view.translation.UiTranslationManager;
+
+import com.android.internal.annotations.Immutable;
+
+/**
+ * The class is used to identify an instance of an Activity. The system provides this to services
+ * that need to request operations on a specific Activity. For example, the system provides this in
+ * {@link ContentCaptureContext} to {@link ContentCaptureService} which can use it to issue requests
+ * like {@link UiTranslationManager#startTranslation}.
+ *
+ * @hide
+ */
+@Immutable
+@SystemApi
+public class ActivityId {
+
+ /**
+ * The identifier of the task this activity is in.
+ */
+ private final int mTaskId;
+ /**
+ * The identifier of the activity.
+ */
+ @Nullable
+ private final IBinder mActivityId;
+
+ /**
+ * @hide
+ */
+ public ActivityId(int taskId, @Nullable IBinder activityId) {
+ mTaskId = taskId;
+ mActivityId = activityId;
+ }
+
+ /**
+ * @hide
+ */
+ public ActivityId(@NonNull Parcel source) {
+ mTaskId = source.readInt();
+ mActivityId = source.readStrongBinder();
+ }
+
+ /**
+ * The identifier of the task this activity is in.
+ * @hide
+ */
+ @TestApi
+ public int getTaskId() {
+ return mTaskId;
+ }
+
+ /**
+ * The identifier of the activity. In some case, this value may be null, e.g. the child session
+ * of content capture.
+ * @hide
+ */
+ @Nullable
+ @TestApi
+ public IBinder getToken() {
+ return mActivityId;
+ }
+
+ /**
+ * @hide
+ */
+ public void writeToParcel(@NonNull Parcel dest, int parcelableFlags) {
+ dest.writeInt(mTaskId);
+ dest.writeStrongBinder(mActivityId);
+ }
+
+ @Override
+ public String toString() {
+ return "ActivityId { taskId = " + mTaskId + ", activityId = " + mActivityId + " }";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ActivityId that = (ActivityId) o;
+ if (mTaskId != that.mTaskId) {
+ return false;
+ }
+ return mActivityId != null
+ ? mActivityId.equals(that.mActivityId)
+ : that.mActivityId == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mTaskId;
+ result = 31 * result + (mActivityId != null ? mActivityId.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 85cfe83..22492cc 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -564,10 +564,6 @@
@VisibleForTesting
public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme)
throws IOException, XmlPullParserException {
- if (isDeviceToDeviceMigration()) {
- return IncludeExcludeRules.emptyRules();
- }
-
Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap;
ArraySet<PathWithRequiredFlags> manifestExcludeSet;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 3701ea8..829b6cd 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -20,11 +20,15 @@
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.storage.StorageManager;
@@ -96,6 +100,14 @@
public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
"fakeClientSideEncryption";
+ /**
+ * When this change is enabled, include / exclude rules specified via
+ * {@code android:fullBackupContent} are ignored during D2D transfers.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long IGNORE_FULL_BACKUP_CONTENT_IN_D2D = 180523564L;
+
@StringDef({
ConfigSection.CLOUD_BACKUP,
ConfigSection.DEVICE_TRANSFER
@@ -527,7 +539,10 @@
}
}
- // TODO(b/180523564): Ignore the old config for apps targeting Android S+ during D2D.
+ if (operationType == OperationType.MIGRATION
+ && CompatChanges.isChangeEnabled(IGNORE_FULL_BACKUP_CONTENT_IN_D2D)) {
+ return;
+ }
if (mFullBackupContent != 0) {
// Fall back to the old config.
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
index b3f9e31..33f8302 100644
--- a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -19,7 +19,9 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.graphics.Bitmap;
import android.os.Binder;
@@ -220,6 +222,72 @@
}
/**
+ * Resets the temporary service implementation to the default component.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS)
+ public void resetTemporaryService(@UserIdInt int userId) {
+ if (mService == null) {
+ Log.e(TAG, "resetTemporaryService called, but no ContentSuggestionsManager "
+ + "configured");
+ return;
+ }
+ try {
+ mService.resetTemporaryService(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Temporarily sets the service implementation.
+ *
+ * @param userId user Id to set the temporary service on.
+ * @param serviceName name of the new component
+ * @param duration how long the change will be valid (the service will be automatically reset
+ * to the default component after this timeout expires).
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS)
+ public void setTemporaryService(
+ @UserIdInt int userId, @NonNull String serviceName, int duration) {
+ if (mService == null) {
+ Log.e(TAG, "setTemporaryService called, but no ContentSuggestionsManager "
+ + "configured");
+ return;
+ }
+ try {
+ mService.setTemporaryService(userId, serviceName, duration);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets whether the default service should be used.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS)
+ public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+ if (mService == null) {
+ Log.e(TAG, "setDefaultServiceEnabled called, but no ContentSuggestionsManager "
+ + "configured");
+ return;
+ }
+ try {
+ mService.setDefaultServiceEnabled(userId, enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback to receive content selections from
* {@link #suggestContentSelections(SelectionsRequest, Executor, SelectionsCallback)}.
*/
diff --git a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
index 8e6338b..9350eeb 100644
--- a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
+++ b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
@@ -45,4 +45,7 @@
in IClassificationsCallback callback);
void notifyInteraction(int userId, in String requestId, in Bundle interaction);
void isEnabled(int userId, in IResultReceiver receiver);
+ void resetTemporaryService(int userId);
+ void setTemporaryService(int userId, in String serviceName, int duration);
+ void setDefaultServiceEnabled(int userId, boolean enabled);
}
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index 132af4b..dd2ba7d 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -29,6 +29,7 @@
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import java.util.ArrayList;
import java.util.List;
@@ -45,7 +46,7 @@
private String mId;
private CharSequence mUserName;
private Icon mUserIcon;
- private int mUid;
+ private UserHandle mUserHandle;
private Uri mContactUri;
private String mPackageName;
private String mBirthdayText;
@@ -64,7 +65,7 @@
mUserName = b.mUserName;
mUserIcon = b.mUserIcon;
mContactUri = b.mContactUri;
- mUid = b.mUid;
+ mUserHandle = b.mUserHandle;
mPackageName = b.mPackageName;
mBirthdayText = b.mBirthdayText;
mLastInteractionTimestamp = b.mLastInteractionTimestamp;
@@ -95,8 +96,8 @@
return mContactUri;
}
- public int getUid() {
- return mUid;
+ public UserHandle getUserHandle() {
+ return mUserHandle;
}
public String getPackageName() {
@@ -165,7 +166,7 @@
Builder builder =
new Builder(mId, mUserName.toString(), mUserIcon, mIntent);
builder.setContactUri(mContactUri);
- builder.setUid(mUid);
+ builder.setUserHandle(mUserHandle);
builder.setPackageName(mPackageName);
builder.setBirthdayText(mBirthdayText);
builder.setLastInteractionTimestamp(mLastInteractionTimestamp);
@@ -186,7 +187,7 @@
private CharSequence mUserName;
private Icon mUserIcon;
private Uri mContactUri;
- private int mUid;
+ private UserHandle mUserHandle;
private String mPackageName;
private String mBirthdayText;
private long mLastInteractionTimestamp;
@@ -212,7 +213,7 @@
mId = info.getId();
mUserName = info.getLabel();
mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
- mUid = info.getUserId();
+ mUserHandle = info.getUserHandle();
mPackageName = info.getPackage();
mContactUri = getContactUri(info);
}
@@ -222,7 +223,7 @@
mId = info.getId();
mUserName = info.getLabel();
mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
- mUid = info.getUserId();
+ mUserHandle = info.getUserHandle();
mPackageName = info.getPackage();
mContactUri = getContactUri(info);
mStatuses = channel.getStatuses();
@@ -265,9 +266,9 @@
return this;
}
- /** Sets the associated uid. */
- public Builder setUid(int uid) {
- mUid = uid;
+ /** Sets the associated {@code userHandle}. */
+ public Builder setUserHandle(UserHandle userHandle) {
+ mUserHandle = userHandle;
return this;
}
@@ -349,7 +350,7 @@
mUserName = in.readCharSequence();
mUserIcon = in.readParcelable(Icon.class.getClassLoader());
mContactUri = in.readParcelable(Uri.class.getClassLoader());
- mUid = in.readInt();
+ mUserHandle = in.readParcelable(UserHandle.class.getClassLoader());
mPackageName = in.readString();
mBirthdayText = in.readString();
mLastInteractionTimestamp = in.readLong();
@@ -375,7 +376,7 @@
dest.writeCharSequence(mUserName);
dest.writeParcelable(mUserIcon, flags);
dest.writeParcelable(mContactUri, flags);
- dest.writeInt(mUid);
+ dest.writeParcelable(mUserHandle, flags);
dest.writeString(mPackageName);
dest.writeString(mBirthdayText);
dest.writeLong(mLastInteractionTimestamp);
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 73a9cec..94ab0dd 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -71,6 +71,7 @@
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
private IBinder mAssistToken;
+ private IBinder mShareableActivityToken;
/**
* It is only non-null if the process is the first time to launch activity. It is only an
* optimization for quick look up of the interface so the field is ignored for comparison.
@@ -95,7 +96,7 @@
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
- client, mAssistToken, mFixedRotationAdjustments);
+ client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -119,7 +120,7 @@
List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
IActivityClientController activityClientController,
- FixedRotationAdjustments fixedRotationAdjustments) {
+ FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
instance = new LaunchActivityItem();
@@ -127,7 +128,7 @@
setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
voiceInteractor, procState, state, persistentState, pendingResults,
pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
- activityClientController, fixedRotationAdjustments);
+ activityClientController, fixedRotationAdjustments, shareableActivityToken);
return instance;
}
@@ -135,7 +136,7 @@
@Override
public void recycle() {
setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
- null, false, null, null, null, null);
+ null, false, null, null, null, null, null);
ObjectPool.recycle(this);
}
@@ -164,6 +165,7 @@
dest.writeStrongBinder(mAssistToken);
dest.writeStrongInterface(mActivityClientController);
dest.writeTypedObject(mFixedRotationAdjustments, flags);
+ dest.writeStrongBinder(mShareableActivityToken);
}
/** Read from Parcel. */
@@ -181,7 +183,7 @@
in.readTypedObject(ProfilerInfo.CREATOR),
in.readStrongBinder(),
IActivityClientController.Stub.asInterface(in.readStrongBinder()),
- in.readTypedObject(FixedRotationAdjustments.CREATOR));
+ in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder());
}
public static final @NonNull Creator<LaunchActivityItem> CREATOR =
@@ -219,7 +221,8 @@
&& mIsForward == other.mIsForward
&& Objects.equals(mProfilerInfo, other.mProfilerInfo)
&& Objects.equals(mAssistToken, other.mAssistToken)
- && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments);
+ && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments)
+ && Objects.equals(mShareableActivityToken, other.mShareableActivityToken);
}
@Override
@@ -241,6 +244,7 @@
result = 31 * result + Objects.hashCode(mProfilerInfo);
result = 31 * result + Objects.hashCode(mAssistToken);
result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
+ result = 31 * result + Objects.hashCode(mShareableActivityToken);
return result;
}
@@ -277,7 +281,8 @@
+ ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
+ ",pendingNewIntents=" + mPendingNewIntents + ",options=" + mActivityOptions
+ ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken
- + ",rotationAdj=" + mFixedRotationAdjustments + "}";
+ + ",rotationAdj=" + mFixedRotationAdjustments
+ + ",shareableActivityToken=" + mShareableActivityToken + "}";
}
// Using the same method to set and clear values to make sure we don't forget anything
@@ -288,7 +293,7 @@
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
IBinder assistToken, IActivityClientController activityClientController,
- FixedRotationAdjustments fixedRotationAdjustments) {
+ FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
instance.mIntent = intent;
instance.mIdent = ident;
instance.mInfo = info;
@@ -308,5 +313,6 @@
instance.mAssistToken = assistToken;
instance.mActivityClientController = activityClientController;
instance.mFixedRotationAdjustments = fixedRotationAdjustments;
+ instance.mShareableActivityToken = shareableActivityToken;
}
}
diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java
index 71a800f..066aada 100644
--- a/core/java/android/app/time/LocationTimeZoneManager.java
+++ b/core/java/android/app/time/LocationTimeZoneManager.java
@@ -37,7 +37,7 @@
/**
* The name of the service for shell commands
*/
- public static final String SHELL_COMMAND_SERVICE_NAME = "location_time_zone_manager";
+ public static final String SERVICE_NAME = "location_time_zone_manager";
/**
* A shell command that starts the service (after stop).
diff --git a/core/java/android/companion/DeviceNotAssociatedException.java b/core/java/android/companion/DeviceNotAssociatedException.java
index bebb6c9..f8a7a7c 100644
--- a/core/java/android/companion/DeviceNotAssociatedException.java
+++ b/core/java/android/companion/DeviceNotAssociatedException.java
@@ -23,7 +23,7 @@
* An exception for a case when a given device was not
* {@link CompanionDeviceManager#associate associated} to the calling app.
*/
-public class DeviceNotAssociatedException extends Exception {
+public class DeviceNotAssociatedException extends RuntimeException {
/** @hide */
public DeviceNotAssociatedException(@Nullable String deviceName) {
super("Device not associated with the current app: " + deviceName);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d53d20a..d352b27 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6755,6 +6755,12 @@
*/
private static final int LOCAL_FLAG_FROM_PROTECTED_COMPONENT = 1 << 2;
+ /**
+ * Local flag indicating this instance had unfiltered extras copied into it. This could be
+ * from either {@link #putExtras(Intent)} when an unparceled Intent is provided or {@link
+ * #putExtras(Bundle)} when the provided Bundle has not been unparceled.
+ */
+ private static final int LOCAL_FLAG_UNFILTERED_EXTRAS = 1 << 3;
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// toUri() and parseUri() options.
@@ -10009,6 +10015,15 @@
mExtras.putAll(src.mExtras);
}
}
+ // If the provided Intent was unparceled and this is not an Intent delivered to a protected
+ // component then mark the extras as unfiltered. An Intent delivered to a protected
+ // component had to come from a trusted component, and if unfiltered data was copied to the
+ // delivered Intent then it would have been reported when that Intent left the sending
+ // process.
+ if ((src.mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
+ && (src.mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+ mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
+ }
return this;
}
@@ -10023,6 +10038,10 @@
* @see #removeExtra
*/
public @NonNull Intent putExtras(@NonNull Bundle extras) {
+ // If the provided Bundle has not yet been unparceled then treat this as unfiltered extras.
+ if (extras.isParcelled()) {
+ mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
+ }
if (mExtras == null) {
mExtras = new Bundle();
}
@@ -11328,10 +11347,13 @@
}
// Detect cases where we're about to launch a potentially unsafe intent
- if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
- && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0
- && StrictMode.vmUnsafeIntentLaunchEnabled()) {
- StrictMode.onUnsafeIntentLaunch(this);
+ if (StrictMode.vmUnsafeIntentLaunchEnabled()) {
+ if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
+ && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+ StrictMode.onUnsafeIntentLaunch(this);
+ } else if ((mLocalFlags & LOCAL_FLAG_UNFILTERED_EXTRAS) != 0) {
+ StrictMode.onUnsafeIntentLaunch(this);
+ }
}
}
diff --git a/core/java/android/content/pm/AppSearchPerson.java b/core/java/android/content/pm/AppSearchPerson.java
index d70ac91..66295eb 100644
--- a/core/java/android/content/pm/AppSearchPerson.java
+++ b/core/java/android/content/pm/AppSearchPerson.java
@@ -42,7 +42,7 @@
public static final String KEY_IS_BOT = "isBot";
public static final String KEY_IS_IMPORTANT = "isImportant";
- private AppSearchPerson(@NonNull GenericDocument document) {
+ public AppSearchPerson(@NonNull GenericDocument document) {
super(document);
}
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index ebe202b..5af3b5a 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -28,7 +28,6 @@
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.PersistableBundle;
-import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -53,17 +52,23 @@
/** The name of the schema type for {@link ShortcutInfo} documents.*/
public static final String SCHEMA_TYPE = "Shortcut";
- public static final String KEY_PACKAGE_NAME = "packageName";
public static final String KEY_ACTIVITY = "activity";
- public static final String KEY_TITLE = "title";
- public static final String KEY_TEXT = "text";
+ public static final String KEY_SHORT_LABEL = "shortLabel";
+ public static final String KEY_SHORT_LABEL_RES_ID = "shortLabelResId";
+ public static final String KEY_SHORT_LABEL_RES_NAME = "shortLabelResName";
+ public static final String KEY_LONG_LABEL = "longLabel";
+ public static final String KEY_LONG_LABEL_RES_ID = "longLabelResId";
+ public static final String KEY_LONG_LABEL_RES_NAME = "longLabelResName";
public static final String KEY_DISABLED_MESSAGE = "disabledMessage";
+ public static final String KEY_DISABLED_MESSAGE_RES_ID = "disabledMessageResId";
+ public static final String KEY_DISABLED_MESSAGE_RES_NAME = "disabledMessageResName";
public static final String KEY_CATEGORIES = "categories";
public static final String KEY_INTENTS = "intents";
public static final String KEY_INTENT_PERSISTABLE_EXTRAS = "intentPersistableExtras";
public static final String KEY_PERSON = "person";
public static final String KEY_LOCUS_ID = "locusId";
public static final String KEY_RANK = "rank";
+ public static final String KEY_IMPLICIT_RANK = "implicitRank";
public static final String KEY_EXTRAS = "extras";
public static final String KEY_FLAGS = "flags";
public static final String KEY_ICON_RES_ID = "iconResId";
@@ -73,36 +78,62 @@
public static final String KEY_DISABLED_REASON = "disabledReason";
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_PACKAGE_NAME)
- .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
- .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
- .build()
-
- ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TITLE)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_SHORT_LABEL)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
- ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TEXT)
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_SHORT_LABEL_RES_ID)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build()
+
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_SHORT_LABEL_RES_NAME)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .build()
+
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_LONG_LABEL_RES_ID)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build()
+
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL_RES_NAME)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .build()
+
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_DISABLED_MESSAGE)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(
+ KEY_DISABLED_MESSAGE_RES_ID)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build()
+
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(
+ KEY_DISABLED_MESSAGE_RES_NAME)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+ .build()
+
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CATEGORIES)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
@@ -135,6 +166,10 @@
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build()
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_IMPLICIT_RANK)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build()
+
).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(KEY_EXTRAS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build()
@@ -183,13 +218,21 @@
Objects.requireNonNull(shortcutInfo);
return new Builder(shortcutInfo.getId())
.setActivity(shortcutInfo.getActivity())
- .setPackageName(shortcutInfo.getPackage())
- .setTitle(shortcutInfo.getShortLabel())
- .setText(shortcutInfo.getLongLabel())
+ .setNamespace(shortcutInfo.getPackage())
+ .setShortLabel(shortcutInfo.getShortLabel())
+ .setShortLabelResId(shortcutInfo.getShortLabelResourceId())
+ .setShortLabelResName(shortcutInfo.getTitleResName())
+ .setLongLabel(shortcutInfo.getLongLabel())
+ .setLongLabelResId(shortcutInfo.getLongLabelResourceId())
+ .setLongLabelResName(shortcutInfo.getTextResName())
.setDisabledMessage(shortcutInfo.getDisabledMessage())
+ .setDisabledMessageResId(shortcutInfo.getDisabledMessageResourceId())
+ .setDisabledMessageResName(shortcutInfo.getDisabledMessageResName())
.setCategories(shortcutInfo.getCategories())
.setIntents(shortcutInfo.getIntents())
.setRank(shortcutInfo.getRank())
+ .setImplicitRank(shortcutInfo.getImplicitRank()
+ | (shortcutInfo.isRankChanged() ? ShortcutInfo.RANK_CHANGED_BIT : 0))
.setExtras(shortcutInfo.getExtras())
.setCreationTimestampMillis(shortcutInfo.getLastChangedTimestamp())
.setFlags(shortcutInfo.getFlags())
@@ -207,17 +250,8 @@
* @hide
*/
@NonNull
- public ShortcutInfo toShortcutInfo() {
- return toShortcutInfo(UserHandle.myUserId());
- }
-
- /**
- * @hide
- * TODO: This should be @SystemApi when AppSearchShortcutInfo unhides.
- */
- @NonNull
- public ShortcutInfo toShortcutInfo(@UserIdInt final int userId) {
- final String packageName = getPropertyString(KEY_PACKAGE_NAME);
+ public ShortcutInfo toShortcutInfo(@UserIdInt int userId) {
+ final String packageName = getNamespace();
final String activityString = getPropertyString(KEY_ACTIVITY);
final ComponentName activity = activityString == null
? null : ComponentName.unflattenFromString(activityString);
@@ -228,15 +262,24 @@
// @hide and @UnsupportedAppUsage, we could migrate existing usage in platform with
// LauncherApps#getShortcutIconDrawable instead.
final Icon icon = null;
- final String title = getPropertyString(KEY_TITLE);
- final String text = getPropertyString(KEY_TEXT);
+ final String shortLabel = getPropertyString(KEY_SHORT_LABEL);
+ final int shortLabelResId = (int) getPropertyLong(KEY_SHORT_LABEL_RES_ID);
+ final String shortLabelResName = getPropertyString(KEY_SHORT_LABEL_RES_NAME);
+ final String longLabel = getPropertyString(KEY_LONG_LABEL);
+ final int longLabelResId = (int) getPropertyLong(KEY_LONG_LABEL_RES_ID);
+ final String longLabelResName = getPropertyString(KEY_LONG_LABEL_RES_NAME);
final String disabledMessage = getPropertyString(KEY_DISABLED_MESSAGE);
+ final int disabledMessageResId = (int) getPropertyLong(KEY_DISABLED_MESSAGE_RES_ID);
+ final String disabledMessageResName = getPropertyString(KEY_DISABLED_MESSAGE_RES_NAME);
final String[] categories = getPropertyStringArray(KEY_CATEGORIES);
final Set<String> categoriesSet = categories == null
- ? new ArraySet<>() : new ArraySet<>(Arrays.asList(categories));
+ ? null : new ArraySet<>(Arrays.asList(categories));
final String[] intentsStrings = getPropertyStringArray(KEY_INTENTS);
final Intent[] intents = intentsStrings == null
- ? null : Arrays.stream(intentsStrings).map(uri -> {
+ ? new Intent[0] : Arrays.stream(intentsStrings).map(uri -> {
+ if (TextUtils.isEmpty(uri)) {
+ return new Intent(Intent.ACTION_VIEW);
+ }
try {
return Intent.parseUri(uri, /* flags =*/ 0);
} catch (URISyntaxException e) {
@@ -251,15 +294,18 @@
if (intents != null) {
for (int i = 0; i < intents.length; i++) {
final Intent intent = intents[i];
- if (intent != null) {
- intent.replaceExtras(intentExtrases[i].size() == 0 ? null : intentExtrases[i]);
+ if (intent == null || intentExtrases == null || intentExtrases.length <= i
+ || intentExtrases[i] == null || intentExtrases[i].size() == 0) {
+ continue;
}
+ intent.replaceExtras(intentExtrases[i]);
}
}
final Person[] persons = parsePerson(getPropertyDocumentArray(KEY_PERSON));
final String locusIdString = getPropertyString(KEY_LOCUS_ID);
final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString);
final int rank = (int) getPropertyLong(KEY_RANK);
+ final int implicitRank = (int) getPropertyLong(KEY_IMPLICIT_RANK);
final byte[] extrasByte = getPropertyBytes(KEY_EXTRAS);
final PersistableBundle extras = transformToPersistableBundle(extrasByte);
final int flags = parseFlags(getPropertyLongArray(KEY_FLAGS));
@@ -268,12 +314,17 @@
final String iconUri = getPropertyString(KEY_ICON_URI);
final String bitmapPath = getPropertyString(KEY_BITMAP_PATH);
final int disabledReason = (int) getPropertyLong(KEY_DISABLED_REASON);
- return new ShortcutInfo(
- userId, getUri(), packageName, activity, icon, title, 0, null,
- text, 0, null, disabledMessage, 0, null,
- categoriesSet, intents, rank, extras,
+ final ShortcutInfo si = new ShortcutInfo(
+ userId, getUri(), packageName, activity, icon, shortLabel, shortLabelResId,
+ shortLabelResName, longLabel, longLabelResId, longLabelResName, disabledMessage,
+ disabledMessageResId, disabledMessageResName, categoriesSet, intents, rank, extras,
getCreationTimestampMillis(), flags, iconResId, iconResName, bitmapPath, iconUri,
disabledReason, persons, locusId, 0);
+ si.setImplicitRank(implicitRank);
+ if ((implicitRank & ShortcutInfo.RANK_CHANGED_BIT) != 0) {
+ si.setRankChanged();
+ }
+ return si;
}
/** @hide */
@@ -310,9 +361,9 @@
* @hide
*/
@NonNull
- public Builder setTitle(@Nullable final CharSequence shortLabel) {
+ public Builder setShortLabel(@Nullable final CharSequence shortLabel) {
if (!TextUtils.isEmpty(shortLabel)) {
- setPropertyString(KEY_TITLE, Preconditions.checkStringNotEmpty(
+ setPropertyString(KEY_SHORT_LABEL, Preconditions.checkStringNotEmpty(
shortLabel, "shortLabel cannot be empty").toString());
}
return this;
@@ -322,13 +373,50 @@
* @hide
*/
@NonNull
- public Builder setText(@Nullable final CharSequence longLabel) {
+ public Builder setShortLabelResId(@Nullable final int shortLabelResId) {
+ setPropertyLong(KEY_SHORT_LABEL_RES_ID, shortLabelResId);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setShortLabelResName(@Nullable final String shortLabelResName) {
+ if (!TextUtils.isEmpty(shortLabelResName)) {
+ setPropertyString(KEY_SHORT_LABEL_RES_NAME, shortLabelResName);
+ }
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
+ public Builder setLongLabel(@Nullable final CharSequence longLabel) {
if (!TextUtils.isEmpty(longLabel)) {
- setPropertyString(KEY_TEXT, Preconditions.checkStringNotEmpty(
+ setPropertyString(KEY_LONG_LABEL, Preconditions.checkStringNotEmpty(
longLabel, "longLabel cannot be empty").toString());
}
return this;
+ }
+ /**
+ * @hide
+ */
+ @NonNull
+ public Builder setLongLabelResId(@Nullable final int longLabelResId) {
+ setPropertyLong(KEY_LONG_LABEL_RES_ID, longLabelResId);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setLongLabelResName(@Nullable final String longLabelResName) {
+ if (!TextUtils.isEmpty(longLabelResName)) {
+ setPropertyString(KEY_LONG_LABEL_RES_NAME, longLabelResName);
+ }
+ return this;
}
/**
@@ -347,6 +435,25 @@
* @hide
*/
@NonNull
+ public Builder setDisabledMessageResId(@Nullable final int disabledMessageResId) {
+ setPropertyLong(KEY_DISABLED_MESSAGE_RES_ID, disabledMessageResId);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setDisabledMessageResName(@Nullable final String disabledMessageResName) {
+ if (!TextUtils.isEmpty(disabledMessageResName)) {
+ setPropertyString(KEY_DISABLED_MESSAGE_RES_NAME, disabledMessageResName);
+ }
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
public Builder setCategories(@Nullable final Set<String> categories) {
if (categories != null && !categories.isEmpty()) {
setPropertyString(KEY_CATEGORIES, categories.stream().toArray(String[]::new));
@@ -384,9 +491,8 @@
intentExtrases[i] = extras == null
? new byte[0] : transformToByteArray(new PersistableBundle(extras));
}
-
- setPropertyString(KEY_INTENTS, Arrays.stream(intents).map(it ->
- it.toUri(0)).toArray(String[]::new));
+ setPropertyString(KEY_INTENTS, Arrays.stream(intents).map(it -> it.toUri(0))
+ .toArray(String[]::new));
setPropertyBytes(KEY_INTENT_PERSISTABLE_EXTRAS, intentExtrases);
return this;
}
@@ -410,10 +516,14 @@
if (persons == null || persons.length == 0) {
return this;
}
- setPropertyDocument(KEY_PERSON,
- Arrays.stream(persons).map(person -> AppSearchPerson.instance(
- Objects.requireNonNull(person, "persons cannot contain null"))
- ).toArray(AppSearchPerson[]::new));
+ final GenericDocument[] documents = new GenericDocument[persons.length];
+ for (int i = 0; i < persons.length; i++) {
+ final Person person = persons[i];
+ if (person == null) continue;
+ final AppSearchPerson appSearchPerson = AppSearchPerson.instance(person);
+ documents[i] = appSearchPerson;
+ }
+ setPropertyDocument(KEY_PERSON, documents);
return this;
}
@@ -422,8 +532,7 @@
*/
@NonNull
public Builder setRank(final int rank) {
- Preconditions.checkArgument((0 <= rank),
- "Rank cannot be negative or bigger than MAX_RANK");
+ Preconditions.checkArgument((0 <= rank), "Rank cannot be negative");
setPropertyLong(KEY_RANK, rank);
return this;
}
@@ -432,6 +541,15 @@
* @hide
*/
@NonNull
+ public Builder setImplicitRank(final int rank) {
+ setPropertyLong(KEY_IMPLICIT_RANK, rank);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
public Builder setExtras(@Nullable final PersistableBundle extras) {
if (extras != null) {
setPropertyBytes(KEY_EXTRAS, transformToByteArray(extras));
@@ -444,7 +562,7 @@
*/
public Builder setPackageName(@Nullable final String packageName) {
if (!TextUtils.isEmpty(packageName)) {
- setPropertyString(KEY_PACKAGE_NAME, packageName);
+ setNamespace(packageName);
}
return this;
}
@@ -579,7 +697,14 @@
@NonNull
private static Person[] parsePerson(@Nullable final GenericDocument[] persons) {
- return persons == null ? new Person[0] : Arrays.stream(persons).map(it ->
- ((AppSearchPerson) it).toPerson()).toArray(Person[]::new);
+ if (persons == null) return new Person[0];
+ final Person[] ret = new Person[persons.length];
+ for (int i = 0; i < persons.length; i++) {
+ final GenericDocument document = persons[i];
+ if (document == null) continue;
+ final AppSearchPerson person = new AppSearchPerson(document);
+ ret[i] = person.toPerson();
+ }
+ return ret;
}
}
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index b290679..48b634e 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.Activity;
import android.app.AppOpsManager.Mode;
import android.content.ComponentName;
@@ -418,6 +419,7 @@
*
* @hide
*/
+ @TestApi
public boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) {
try {
return mService.canConfigureInteractAcrossProfiles(packageName);
diff --git a/core/java/android/content/pm/DataLoaderParamsParcel.aidl b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
index d40012fd..29d472e 100644
--- a/core/java/android/content/pm/DataLoaderParamsParcel.aidl
+++ b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
@@ -23,7 +23,7 @@
* @hide
*/
parcelable DataLoaderParamsParcel {
- DataLoaderType type;
+ DataLoaderType type = DataLoaderType.NONE;
@utf8InCpp String packageName;
@utf8InCpp String className;
@utf8InCpp String arguments;
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 29a55b7..b345748 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -78,4 +78,7 @@
ParceledListSlice getShortcuts(String packageName, int matchFlags, int userId);
void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId);
+
+ void updateShortcutVisibility(String callingPkg, String packageName, in byte[] certificate,
+ in boolean visible, int userId);
}
\ No newline at end of file
diff --git a/core/java/android/content/pm/InstallationFileParcel.aidl b/core/java/android/content/pm/InstallationFileParcel.aidl
index b7efc19..09d1a32 100644
--- a/core/java/android/content/pm/InstallationFileParcel.aidl
+++ b/core/java/android/content/pm/InstallationFileParcel.aidl
@@ -24,7 +24,7 @@
*/
parcelable InstallationFileParcel {
String name;
- InstallationFileLocation location;
+ InstallationFileLocation location = InstallationFileLocation.UNKNOWN;
long size;
byte[] metadata;
byte[] signature;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 567501c..42cbe35 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1173,7 +1173,6 @@
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
public @Nullable DataLoaderParams getDataLoaderParams() {
try {
DataLoaderParamsParcel data = mSession.getDataLoaderParams();
@@ -1213,7 +1212,6 @@
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes,
@NonNull byte[] metadata, @Nullable byte[] signature) {
try {
@@ -1237,7 +1235,6 @@
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
public void removeFile(@FileLocation int location, @NonNull String name) {
try {
mSession.removeFile(location, name);
@@ -2050,9 +2047,7 @@
* {@hide}
*/
@SystemApi
- @RequiresPermission(allOf = {
- Manifest.permission.INSTALL_PACKAGES,
- Manifest.permission.USE_INSTALLER_V2})
+ @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
this.dataLoaderParams = dataLoaderParams;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9a3fbdc..3bc6144 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3623,11 +3623,26 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for
- * camera. When sensory privacy for the camera is enabled no camera data is send to clients,
+ * microphone. When sensory privacy for the microphone is enabled no microphone data is sent to
+ * clients, e.g. all audio data is silent.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for
+ * camera. When sensory privacy for the camera is enabled no camera data is sent to clients,
* e.g. the view finder in a camera app would appear blank.
*
* @hide
*/
+ @SystemApi
+ @TestApi
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
@@ -3641,17 +3656,6 @@
public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration";
/**
- * Feature for {@link android.view.WindowManager.LayoutParams.backgroundBlurRedius} and
- * {@link android.graphics.drawable.BackgroundBlurDrawable}: the device supports cross-layer
- * blurring.
- *
- * @hide
- */
- @SystemApi
- @SdkConstant(SdkConstantType.FEATURE)
- public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
-
- /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
* a Keystore implementation that can only enforce limited use key in hardware with max usage
* count equals to 1.
@@ -4060,16 +4064,6 @@
public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;
/**
- * Permission flag: The permission is restricted but the app is exempt
- * from the restriction and is allowed to hold this permission in its
- * full form and the exemption is provided by the held roles.
- *
- * @hide
- */
- @SystemApi
- public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 1 << 18;
-
- /**
* Permission flag: This location permission is selected as the level of granularity of
* location accuracy.
* Example: If this flag is set for ACCESS_FINE_LOCATION, FINE location is the selected location
@@ -4098,8 +4092,7 @@
public static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT =
FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
| FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
- | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
- | FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
/**
* Mask for all permission flags.
@@ -4184,20 +4177,11 @@
*/
public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 1 << 2;
- /**
- * Permission allowlist flag: permissions exempted by the system
- * when being granted a role.
- * Permissions can also be exempted by the installer, the system, or on
- * upgrade.
- */
- public static final int FLAG_PERMISSION_ALLOWLIST_ROLE = 1 << 3;
-
/** @hide */
@IntDef(flag = true, prefix = {"FLAG_PERMISSION_WHITELIST_"}, value = {
FLAG_PERMISSION_WHITELIST_SYSTEM,
FLAG_PERMISSION_WHITELIST_INSTALLER,
- FLAG_PERMISSION_WHITELIST_UPGRADE,
- FLAG_PERMISSION_ALLOWLIST_ROLE
+ FLAG_PERMISSION_WHITELIST_UPGRADE
})
@Retention(RetentionPolicy.SOURCE)
public @interface PermissionWhitelistFlags {}
@@ -5229,10 +5213,6 @@
* This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_INSTALLER} flag.
* Can be accessed by pre-installed holders of a dedicated permission or the
* installer on record.
- *
- * <li>one for cases where the system exempts the permission when granting a role.
- * This list corresponds to the {@link #FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can
- * be accessed by pre-installed holders of a dedicated permission.
* </ol>
*
* <p>
@@ -5251,7 +5231,6 @@
* @see #FLAG_PERMISSION_WHITELIST_SYSTEM
* @see #FLAG_PERMISSION_WHITELIST_UPGRADE
* @see #FLAG_PERMISSION_WHITELIST_INSTALLER
- * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @throws SecurityException if you try to access a whitelist that you have no access to.
*/
@@ -5291,10 +5270,6 @@
* This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_INSTALLER} flag.
* Can be modified by pre-installed holders of a dedicated permission or the installer
* on record.
- *
- * <li>one for cases where the system exempts the permission when permission when
- * granting a role. This list corresponds to the {@link #FLAG_PERMISSION_ALLOWLIST_ROLE}
- * flag. Can be modified by pre-installed holders of a dedicated permission.
* </ol>
*
* <p>You need to specify the whitelists for which to set the whitelisted permissions
@@ -5318,7 +5293,6 @@
* @see #FLAG_PERMISSION_WHITELIST_SYSTEM
* @see #FLAG_PERMISSION_WHITELIST_UPGRADE
* @see #FLAG_PERMISSION_WHITELIST_INSTALLER
- * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @throws SecurityException if you try to modify a whitelist that you have no access to.
*/
@@ -5388,7 +5362,6 @@
* @see #FLAG_PERMISSION_WHITELIST_SYSTEM
* @see #FLAG_PERMISSION_WHITELIST_UPGRADE
* @see #FLAG_PERMISSION_WHITELIST_INSTALLER
- * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @throws SecurityException if you try to modify a whitelist that you have no access to.
*/
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 0e70a3e..83baca6 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -411,14 +411,6 @@
public static final int FLAG_IMMUTABLY_RESTRICTED = 1<<4;
/**
- * Flag for {@link #flags}, corresponding to <code>installerExemptIgnored</code>
- * value of {@link android.R.attr#permissionFlags}.
- *
- * <p> Modifier for permission restriction. This permission cannot be exempted by the installer.
- */
- public static final int FLAG_INSTALLER_EXEMPT_IGNORED = 1 << 5;
-
- /**
* Flag for {@link #flags}, indicating that this permission has been
* installed into the system's globally defined permissions.
*/
@@ -724,11 +716,6 @@
}
/** @hide */
- public boolean isInstallerExemptIgnored() {
- return (flags & PermissionInfo.FLAG_INSTALLER_EXEMPT_IGNORED) != 0;
- }
-
- /** @hide */
public boolean isAppOp() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
}
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 5f80ba1..275e81c 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -68,7 +68,8 @@
private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
- private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
+ /** @hide */
+ public static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
/** @hide */
public static final int RANK_NOT_SET = Integer.MAX_VALUE;
@@ -1595,6 +1596,9 @@
*/
@Nullable
public Intent[] getIntents() {
+ if (mIntents == null) {
+ return null;
+ }
final Intent[] ret = new Intent[mIntents.length];
for (int i = 0; i < ret.length; i++) {
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 35c99a1..d3bac79 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -39,6 +39,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
@@ -771,4 +772,20 @@
}
}
+ /**
+ * Granting another app the access to the shortcuts you own. You must provide the package name
+ * and their SHA256 certificate digest in order to granting the access.
+ *
+ * Once granted, the other app can retain a copy of all the shortcuts you own when calling
+ * {@link LauncherApps#getShortcuts(LauncherApps.ShortcutQuery, UserHandle)}.
+ */
+ public void updateShortcutVisibility(@NonNull final String packageName,
+ @Nullable final byte[] certificate, final boolean visible) {
+ try {
+ mService.updateShortcutVisibility(mContext.getPackageName(), packageName, certificate,
+ visible, injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index d81dff8..cfb6e1b 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
@@ -47,6 +48,7 @@
*
* @hide
*/
+@TestApi
public class UserInfo implements Parcelable {
/**
diff --git a/core/java/android/content/pm/verify/domain/DomainOwner.aidl b/core/java/android/content/pm/verify/domain/DomainOwner.aidl
new file mode 100644
index 0000000..41366d1
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainOwner.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.content.pm.verify.domain;
+
+parcelable DomainOwner;
diff --git a/core/java/android/content/pm/verify/domain/DomainOwner.java b/core/java/android/content/pm/verify/domain/DomainOwner.java
new file mode 100644
index 0000000..b050f5d
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainOwner.java
@@ -0,0 +1,219 @@
+/*
+ * 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.content.pm.verify.domain;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * @hide
+ */
+@SystemApi
+@DataClass(genParcelable = true, genEqualsHashCode = true, genAidl = true, genToString = true)
+public final class DomainOwner implements Parcelable {
+
+ /**
+ * Package name of that owns the domain.
+ */
+ @NonNull
+ private final String mPackageName;
+
+ /**
+ * Whether or not this owner can be automatically overridden.
+ *
+ * @see DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)
+ */
+ private final boolean mOverrideable;
+
+
+
+ // Code below generated by codegen v1.0.22.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new DomainOwner.
+ *
+ * @param packageName
+ * Package name of that owns the domain.
+ * @param overrideable
+ * Whether or not this owner can be automatically overridden. If all owners for a domain are
+ * overrideable, then calling
+ * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+ * Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
+ * of the owners are non-overrideable, then
+ * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
+ * boolean)} must be called with false to disable all of the other owners before this domain can
+ * be taken by a new owner through
+ * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+ * Set, boolean)}.
+ */
+ @DataClass.Generated.Member
+ public DomainOwner(
+ @NonNull String packageName,
+ boolean overrideable) {
+ this.mPackageName = packageName;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mPackageName);
+ this.mOverrideable = overrideable;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Package name of that owns the domain.
+ */
+ @DataClass.Generated.Member
+ public @NonNull String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Whether or not this owner can be automatically overridden. If all owners for a domain are
+ * overrideable, then calling
+ * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+ * Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
+ * of the owners are non-overrideable, then
+ * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
+ * boolean)} must be called with false to disable all of the other owners before this domain can
+ * be taken by a new owner through
+ * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+ * Set, boolean)}.
+ */
+ @DataClass.Generated.Member
+ public boolean isOverrideable() {
+ return mOverrideable;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "DomainOwner { " +
+ "packageName = " + mPackageName + ", " +
+ "overrideable = " + mOverrideable +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@android.annotation.Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(DomainOwner other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ DomainOwner that = (DomainOwner) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && java.util.Objects.equals(mPackageName, that.mPackageName)
+ && mOverrideable == that.mOverrideable;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mPackageName);
+ _hash = 31 * _hash + Boolean.hashCode(mOverrideable);
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mOverrideable) flg |= 0x2;
+ dest.writeByte(flg);
+ dest.writeString(mPackageName);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ DomainOwner(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ boolean overrideable = (flg & 0x2) != 0;
+ String packageName = in.readString();
+
+ this.mPackageName = packageName;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mPackageName);
+ this.mOverrideable = overrideable;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<DomainOwner> CREATOR
+ = new Parcelable.Creator<DomainOwner>() {
+ @Override
+ public DomainOwner[] newArray(int size) {
+ return new DomainOwner[size];
+ }
+
+ @Override
+ public DomainOwner createFromParcel(@NonNull android.os.Parcel in) {
+ return new DomainOwner(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1614119379978L,
+ codegenVersion = "1.0.22",
+ sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java",
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final boolean mOverrideable\nclass DomainOwner extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genEqualsHashCode=true, genAidl=true, genToString=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/verify/domain/DomainSet.aidl b/core/java/android/content/pm/verify/domain/DomainSet.aidl
new file mode 100644
index 0000000..fab131d
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainSet.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.content.pm.verify.domain;
+
+parcelable DomainSet;
diff --git a/core/java/android/content/pm/verify/domain/DomainSet.java b/core/java/android/content/pm/verify/domain/DomainSet.java
new file mode 100644
index 0000000..243ff08
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainSet.java
@@ -0,0 +1,160 @@
+/*
+ * 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.content.pm.verify.domain;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Set;
+
+/**
+ * Wraps an input set of domains from the client process, to be sent to the server. Handles cases
+ * where the data size is too large by writing data using {@link Parcel#writeBlob(byte[])}.
+ *
+ * @hide
+ */
+@DataClass(genParcelable = true, genAidl = true, genEqualsHashCode = true)
+public class DomainSet implements Parcelable {
+
+ @NonNull
+ private final Set<String> mDomains;
+
+ private void parcelDomains(@NonNull Parcel dest, @SuppressWarnings("unused") int flags) {
+ DomainVerificationUtils.writeHostSet(dest, mDomains);
+ }
+
+ private Set<String> unparcelDomains(@NonNull Parcel in) {
+ return DomainVerificationUtils.readHostSet(in);
+ }
+
+
+
+ // Code below generated by codegen v1.0.22.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
+ // /DomainSet.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ public DomainSet(
+ @NonNull Set<String> domains) {
+ this.mDomains = domains;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDomains);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull Set<String> getDomains() {
+ return mDomains;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@android.annotation.Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(DomainSet other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ DomainSet that = (DomainSet) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && java.util.Objects.equals(mDomains, that.mDomains);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mDomains);
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ parcelDomains(dest, flags);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected DomainSet(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ Set<String> domains = unparcelDomains(in);
+
+ this.mDomains = domains;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDomains);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<DomainSet> CREATOR
+ = new Parcelable.Creator<DomainSet>() {
+ @Override
+ public DomainSet[] newArray(int size) {
+ return new DomainSet[size];
+ }
+
+ @Override
+ public DomainSet createFromParcel(@NonNull Parcel in) {
+ return new DomainSet(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1613169242020L,
+ codegenVersion = "1.0.22",
+ sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainSet.java",
+ inputSignatures = "private final @android.annotation.NonNull java.util.Set<java.lang.String> mDomains\nprivate void parcelDomains(android.os.Parcel,int)\nprivate java.util.Set<java.lang.String> unparcelDomains(android.os.Parcel)\nclass DomainSet extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genEqualsHashCode=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
index 7afbe1f..8095875 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
@@ -19,7 +19,9 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.pm.PackageManager;
+import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArrayMap;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -34,12 +36,12 @@
* against the digital asset links response from the server hosting that domain.
* <p>
* These values for each domain can be modified through
- * {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)}.
+ * {@link DomainVerificationManager#setDomainVerificationStatus(UUID,
+ * Set, int)}.
*
* @hide
*/
@SystemApi
-@SuppressWarnings("DefaultAnnotationParam")
@DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
genEqualsHashCode = true)
public final class DomainVerificationInfo implements Parcelable {
@@ -71,22 +73,30 @@
private final String mPackageName;
/**
- * Map of host names to their current state. State is an integer, which defaults to
- * {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
- * domain verification agent (the intended consumer of this API), which can be equal
- * to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
- * greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
- * any unsuccessful response.
+ * Map of host names to their current state. State is an integer, which defaults to {@link
+ * DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
+ * verification agent (the intended consumer of this API), which can be equal to {@link
+ * DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
+ * DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
* <p>
- * Any value non-inclusive between those 2 values are reserved for use by the system.
- * The domain verification agent may be able to act on these reserved values, and this
- * ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
- * It is expected that the agent attempt to verify all domains that it can modify the
- * state of, even if it does not understand the meaning of those values.
+ * Any value non-inclusive between those 2 values are reserved for use by the system. The domain
+ * verification agent may be able to act on these reserved values, and this ability can be
+ * queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
+ * the agent attempt to verify all domains that it can modify the state of, even if it does not
+ * understand the meaning of those values.
*/
@NonNull
private final Map<String, Integer> mHostToStateMap;
+ private void parcelHostToStateMap(Parcel dest, @SuppressWarnings("unused") int flags) {
+ DomainVerificationUtils.writeHostMap(dest, mHostToStateMap);
+ }
+
+ private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
+ return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
+ DomainVerificationUserSelection.class.getClassLoader());
+ }
+
// Code below generated by codegen v1.0.22.
@@ -95,7 +105,8 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
+ // /DomainVerificationInfo.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -123,18 +134,17 @@
* @param packageName
* The package name that this data corresponds to.
* @param hostToStateMap
- * Map of host names to their current state. State is an integer, which defaults to
- * {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
- * domain verification agent (the intended consumer of this API), which can be equal
- * to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
- * greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
- * any unsuccessful response.
+ * Map of host names to their current state. State is an integer, which defaults to {@link
+ * DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
+ * verification agent (the intended consumer of this API), which can be equal to {@link
+ * DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
+ * DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
* <p>
- * Any value non-inclusive between those 2 values are reserved for use by the system.
- * The domain verification agent may be able to act on these reserved values, and this
- * ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
- * It is expected that the agent attempt to verify all domains that it can modify the
- * state of, even if it does not understand the meaning of those values.
+ * Any value non-inclusive between those 2 values are reserved for use by the system. The domain
+ * verification agent may be able to act on these reserved values, and this ability can be
+ * queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
+ * the agent attempt to verify all domains that it can modify the state of, even if it does not
+ * understand the meaning of those values.
* @hide
*/
@DataClass.Generated.Member
@@ -185,18 +195,17 @@
}
/**
- * Map of host names to their current state. State is an integer, which defaults to
- * {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
- * domain verification agent (the intended consumer of this API), which can be equal
- * to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
- * greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
- * any unsuccessful response.
+ * Map of host names to their current state. State is an integer, which defaults to {@link
+ * DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
+ * verification agent (the intended consumer of this API), which can be equal to {@link
+ * DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
+ * DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
* <p>
- * Any value non-inclusive between those 2 values are reserved for use by the system.
- * The domain verification agent may be able to act on these reserved values, and this
- * ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
- * It is expected that the agent attempt to verify all domains that it can modify the
- * state of, even if it does not understand the meaning of those values.
+ * Any value non-inclusive between those 2 values are reserved for use by the system. The domain
+ * verification agent may be able to act on these reserved values, and this ability can be
+ * queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
+ * the agent attempt to verify all domains that it can modify the state of, even if it does not
+ * understand the meaning of those values.
*/
@DataClass.Generated.Member
public @NonNull Map<String,Integer> getHostToStateMap() {
@@ -260,13 +269,13 @@
@Override
@DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
sParcellingForIdentifier.parcel(mIdentifier, dest, flags);
dest.writeString(mPackageName);
- dest.writeMap(mHostToStateMap);
+ parcelHostToStateMap(dest, flags);
}
@Override
@@ -276,14 +285,13 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ DomainVerificationInfo(@NonNull android.os.Parcel in) {
+ /* package-private */ DomainVerificationInfo(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
UUID identifier = sParcellingForIdentifier.unparcel(in);
String packageName = in.readString();
- Map<String,Integer> hostToStateMap = new java.util.LinkedHashMap<>();
- in.readMap(hostToStateMap, Integer.class.getClassLoader());
+ Map<String,Integer> hostToStateMap = unparcelHostToStateMap(in);
this.mIdentifier = identifier;
com.android.internal.util.AnnotationValidations.validate(
@@ -307,16 +315,16 @@
}
@Override
- public DomainVerificationInfo createFromParcel(@NonNull android.os.Parcel in) {
+ public DomainVerificationInfo createFromParcel(@NonNull Parcel in) {
return new DomainVerificationInfo(in);
}
};
@DataClass.Generated(
- time = 1611862790369L,
+ time = 1613002530369L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java",
- inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nclass DomainVerificationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
+ inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
index cbb3baa..11402af 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
@@ -239,7 +239,15 @@
* {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
*
* Enabling an unverified domain will allow an application to open it, but this can only occur
- * if no other app on the device is approved for the domain.
+ * if no other app on the device is approved for a higher approval level. This can queried
+ * using {@link #getOwnersForDomain(String)}.
+ *
+ * If all owners for a domain are {@link DomainOwner#isOverrideable()}, then calling this to
+ * enable that domain will disable all other owners.
+ *
+ * On the other hand, if any of the owners are non-overrideable, then this must be called with
+ * false for all of the other owners to disable them before the domain can be taken by a new
+ * owner.
*
* @param domainSetId See {@link DomainVerificationInfo#getIdentifier()}.
* @param domains The domains to toggle the state of.
@@ -276,6 +284,19 @@
throws NameNotFoundException;
/**
+ * For the given domain, return all apps which are approved to open it in a
+ * greater than 0 priority. This does not mean that all apps can actually open
+ * 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.
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
+ List<DomainOwner> getOwnersForDomain(@NonNull String domain);
+
+ /**
* Thrown if a {@link DomainVerificationInfo#getIdentifier()}} or an associated set of domains
* provided by the caller is no longer valid. This may be recoverable, and the caller should
* re-query the package name associated with the ID using
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java b/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
index 5938def..8b9865c 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
@@ -21,11 +21,9 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
-import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -89,7 +87,7 @@
int state) throws IllegalArgumentException, NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
- new ArrayList<>(domains), state);
+ new DomainSet(domains), state);
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {
@@ -126,7 +124,7 @@
throws IllegalArgumentException, NameNotFoundException {
try {
mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
- new ArrayList<>(domains), enabled, mContext.getUserId());
+ new DomainSet(domains), enabled, mContext.getUserId());
} catch (Exception e) {
Exception converted = rethrow(e, domainSetId);
if (converted instanceof NameNotFoundException) {
@@ -158,6 +156,16 @@
}
}
+ @NonNull
+ @Override
+ public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
+ try {
+ return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
return rethrow(exception, domainSetId, null);
}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java b/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
index 473abce..65f6d7c 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Intent;
+import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.DataClass;
@@ -27,11 +28,11 @@
import java.util.Set;
/**
- * Request object sent in the {@link Intent} that's broadcast to the domain verification
- * agent, retrieved through {@link DomainVerificationManager#EXTRA_VERIFICATION_REQUEST}.
+ * Request object sent in the {@link Intent} that's broadcast to the domain verification agent,
+ * retrieved through {@link DomainVerificationManager#EXTRA_VERIFICATION_REQUEST}.
* <p>
- * This contains the set of packages which have been invalidated and will require
- * re-verification. The exact domains can be retrieved with
+ * This contains the set of packages which have been invalidated and will require re-verification.
+ * The exact domains can be retrieved with
* {@link DomainVerificationManager#getDomainVerificationInfo(String)}
*
* @hide
@@ -42,14 +43,22 @@
public final class DomainVerificationRequest implements Parcelable {
/**
- * The package names of the apps that need to be verified. The receiver should call
- * {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
- * these values to get the actual set of domains that need to be acted on.
+ * The package names of the apps that need to be verified. The receiver should call {@link
+ * DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
+ * the actual set of domains that need to be acted on.
*/
@NonNull
@DataClass.ParcelWith(Parcelling.BuiltIn.ForStringSet.class)
private final Set<String> mPackageNames;
+ private void parcelPackageNames(@NonNull Parcel dest, @SuppressWarnings("unused") int flags) {
+ DomainVerificationUtils.writeHostSet(dest, mPackageNames);
+ }
+
+ private Set<String> unparcelPackageNames(@NonNull Parcel in) {
+ return DomainVerificationUtils.readHostSet(in);
+ }
+
// Code below generated by codegen v1.0.22.
@@ -58,7 +67,8 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
+ // /DomainVerificationRequest.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -69,9 +79,9 @@
* Creates a new DomainVerificationRequest.
*
* @param packageNames
- * The package names of the apps that need to be verified. The receiver should call
- * {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
- * these values to get the actual set of domains that need to be acted on.
+ * The package names of the apps that need to be verified. The receiver should call {@link
+ * DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
+ * the actual set of domains that need to be acted on.
* @hide
*/
@DataClass.Generated.Member
@@ -85,9 +95,9 @@
}
/**
- * The package names of the apps that need to be verified. The receiver should call
- * {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
- * these values to get the actual set of domains that need to be acted on.
+ * The package names of the apps that need to be verified. The receiver should call {@link
+ * DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
+ * the actual set of domains that need to be acted on.
*/
@DataClass.Generated.Member
public @NonNull Set<String> getPackageNames() {
@@ -134,11 +144,11 @@
@Override
@DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
- sParcellingForPackageNames.parcel(mPackageNames, dest, flags);
+ parcelPackageNames(dest, flags);
}
@Override
@@ -148,11 +158,11 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ DomainVerificationRequest(@NonNull android.os.Parcel in) {
+ /* package-private */ DomainVerificationRequest(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
- Set<String> packageNames = sParcellingForPackageNames.unparcel(in);
+ Set<String> packageNames = unparcelPackageNames(in);
this.mPackageNames = packageNames;
com.android.internal.util.AnnotationValidations.validate(
@@ -170,16 +180,16 @@
}
@Override
- public DomainVerificationRequest createFromParcel(@NonNull android.os.Parcel in) {
+ public DomainVerificationRequest createFromParcel(@NonNull Parcel in) {
return new DomainVerificationRequest(in);
}
};
@DataClass.Generated(
- time = 1611862814990L,
+ time = 1613169505495L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java",
- inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForStringSet.class) java.util.Set<java.lang.String> mPackageNames\nclass DomainVerificationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false, genEqualsHashCode=true)")
+ inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForStringSet.class) java.util.Set<java.lang.String> mPackageNames\nprivate void parcelPackageNames(android.os.Parcel,int)\nprivate java.util.Set<java.lang.String> unparcelPackageNames(android.os.Parcel)\nclass DomainVerificationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java b/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
index 73346ef..d23f5f1 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
@@ -20,8 +20,10 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
+import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.util.ArrayMap;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -40,29 +42,46 @@
* toggle affects <b>all</b> links and is not based on the verification state of the domains.
* <p>
* Assuming the toggle is enabled, the user can also select additional unverified domains to grant
- * to the application to open, which is reflected in {@link #getHostToUserSelectionMap()}. But only
- * a single application can be approved for a domain unless the applications are both approved. If
- * another application is approved, the user will not be allowed to enable the domain.
+ * to the application to open, which is reflected in {@link #getHostToStateMap()}. But only a single
+ * application can be approved for a domain unless the applications are both approved. If another
+ * application is approved, the user will not be allowed to enable the domain.
* <p>
* These values can be changed through the
* {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
- * boolean)} and
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
+ * boolean)} and {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
* boolean)} APIs.
* <p>
- * Note that because state is per user, if a different user needs to be changed, one will
- * need to use {@link Context#createContextAsUser(UserHandle, int)} and hold the
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
+ * Note that because state is per user, if a different user needs to be changed, one will need to
+ * use {@link Context#createContextAsUser(UserHandle, int)} and hold the {@link
+ * android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
*
* @hide
*/
@SystemApi
@SuppressWarnings("DefaultAnnotationParam")
@DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
- genEqualsHashCode = true)
+ genEqualsHashCode = true, genHiddenConstDefs = true)
public final class DomainVerificationUserSelection implements Parcelable {
/**
+ * The domain is unverified and unselected, and the application is unable to open web links
+ * that resolve to the domain.
+ */
+ public static final int DOMAIN_STATE_NONE = 0;
+
+ /**
+ * The domain has been selected through the
+ * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)}
+ * API, under the assumption it has not been reset by the system.
+ */
+ public static final int DOMAIN_STATE_SELECTED = 1;
+
+ /**
+ * The domain has been previously verified by the domain verification agent.
+ */
+ public static final int DOMAIN_STATE_VERIFIED = 2;
+
+ /**
* @see DomainVerificationInfo#getIdentifier
*/
@NonNull
@@ -88,15 +107,20 @@
private final boolean mLinkHandlingAllowed;
/**
- * Retrieve the existing user selection state for the matching
- * {@link #getPackageName()}, as was previously set by
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
- * boolean)}.
- *
- * @return Map of hosts to enabled state for the given package and user.
+ * Mapping of domain host to state, as defined by {@link DomainState}.
*/
@NonNull
- private final Map<String, Boolean> mHostToUserSelectionMap;
+ private final Map<String, Integer> mHostToStateMap;
+
+ private void parcelHostToStateMap(Parcel dest, @SuppressWarnings("unused") int flags) {
+ DomainVerificationUtils.writeHostMap(dest, mHostToStateMap);
+ }
+
+ @NonNull
+ private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
+ return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
+ DomainVerificationUserSelection.class.getClassLoader());
+ }
@@ -106,14 +130,37 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
- // /DomainVerificationUserSelection.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
+ /** @hide */
+ @android.annotation.IntDef(prefix = "DOMAIN_STATE_", value = {
+ DOMAIN_STATE_NONE,
+ DOMAIN_STATE_SELECTED,
+ DOMAIN_STATE_VERIFIED
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface DomainState {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String domainStateToString(@DomainState int value) {
+ switch (value) {
+ case DOMAIN_STATE_NONE:
+ return "DOMAIN_STATE_NONE";
+ case DOMAIN_STATE_SELECTED:
+ return "DOMAIN_STATE_SELECTED";
+ case DOMAIN_STATE_VERIFIED:
+ return "DOMAIN_STATE_VERIFIED";
+ default: return Integer.toHexString(value);
+ }
+ }
+
/**
* Creates a new DomainVerificationUserSelection.
*
@@ -123,11 +170,8 @@
* The user that this data corresponds to.
* @param linkHandlingAllowed
* Whether or not this package is allowed to open links.
- * @param hostToUserSelectionMap
- * Retrieve the existing user selection state for the matching
- * {@link #getPackageName()}, as was previously set by
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
- * boolean)}.
+ * @param hostToStateMap
+ * Mapping of domain host to state, as defined by {@link DomainState}.
* @hide
*/
@DataClass.Generated.Member
@@ -136,7 +180,7 @@
@NonNull String packageName,
@NonNull UserHandle user,
@NonNull boolean linkHandlingAllowed,
- @NonNull Map<String,Boolean> hostToUserSelectionMap) {
+ @NonNull Map<String,Integer> hostToStateMap) {
this.mIdentifier = identifier;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mIdentifier);
@@ -149,9 +193,9 @@
this.mLinkHandlingAllowed = linkHandlingAllowed;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mLinkHandlingAllowed);
- this.mHostToUserSelectionMap = hostToUserSelectionMap;
+ this.mHostToStateMap = hostToStateMap;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mHostToUserSelectionMap);
+ NonNull.class, null, mHostToStateMap);
// onConstructed(); // You can define this method to get a callback
}
@@ -189,16 +233,11 @@
}
/**
- * Retrieve the existing user selection state for the matching
- * {@link #getPackageName()}, as was previously set by
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
- * boolean)}.
- *
- * @return Map of hosts to enabled state for the given package and user.
+ * Mapping of domain host to state, as defined by {@link DomainState}.
*/
@DataClass.Generated.Member
- public @NonNull Map<String,Boolean> getHostToUserSelectionMap() {
- return mHostToUserSelectionMap;
+ public @NonNull Map<String,Integer> getHostToStateMap() {
+ return mHostToStateMap;
}
@Override
@@ -212,7 +251,7 @@
"packageName = " + mPackageName + ", " +
"user = " + mUser + ", " +
"linkHandlingAllowed = " + mLinkHandlingAllowed + ", " +
- "hostToUserSelectionMap = " + mHostToUserSelectionMap +
+ "hostToStateMap = " + mHostToStateMap +
" }";
}
@@ -233,7 +272,7 @@
&& java.util.Objects.equals(mPackageName, that.mPackageName)
&& java.util.Objects.equals(mUser, that.mUser)
&& mLinkHandlingAllowed == that.mLinkHandlingAllowed
- && java.util.Objects.equals(mHostToUserSelectionMap, that.mHostToUserSelectionMap);
+ && java.util.Objects.equals(mHostToStateMap, that.mHostToStateMap);
}
@Override
@@ -247,7 +286,7 @@
_hash = 31 * _hash + java.util.Objects.hashCode(mPackageName);
_hash = 31 * _hash + java.util.Objects.hashCode(mUser);
_hash = 31 * _hash + Boolean.hashCode(mLinkHandlingAllowed);
- _hash = 31 * _hash + java.util.Objects.hashCode(mHostToUserSelectionMap);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mHostToStateMap);
return _hash;
}
@@ -264,7 +303,7 @@
@Override
@DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -274,7 +313,7 @@
sParcellingForIdentifier.parcel(mIdentifier, dest, flags);
dest.writeString(mPackageName);
dest.writeTypedObject(mUser, flags);
- dest.writeMap(mHostToUserSelectionMap);
+ parcelHostToStateMap(dest, flags);
}
@Override
@@ -284,7 +323,7 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ DomainVerificationUserSelection(@NonNull android.os.Parcel in) {
+ /* package-private */ DomainVerificationUserSelection(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -293,8 +332,7 @@
UUID identifier = sParcellingForIdentifier.unparcel(in);
String packageName = in.readString();
UserHandle user = (UserHandle) in.readTypedObject(UserHandle.CREATOR);
- Map<String,Boolean> hostToUserSelectionMap = new java.util.LinkedHashMap<>();
- in.readMap(hostToUserSelectionMap, Boolean.class.getClassLoader());
+ Map<String,Integer> hostToStateMap = unparcelHostToStateMap(in);
this.mIdentifier = identifier;
com.android.internal.util.AnnotationValidations.validate(
@@ -308,9 +346,9 @@
this.mLinkHandlingAllowed = linkHandlingAllowed;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mLinkHandlingAllowed);
- this.mHostToUserSelectionMap = hostToUserSelectionMap;
+ this.mHostToStateMap = hostToStateMap;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mHostToUserSelectionMap);
+ NonNull.class, null, mHostToStateMap);
// onConstructed(); // You can define this method to get a callback
}
@@ -324,16 +362,16 @@
}
@Override
- public DomainVerificationUserSelection createFromParcel(@NonNull android.os.Parcel in) {
+ public DomainVerificationUserSelection createFromParcel(@NonNull Parcel in) {
return new DomainVerificationUserSelection(in);
}
};
@DataClass.Generated(
- time = 1612829797220L,
+ time = 1613683603297L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java",
- inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Boolean> mHostToUserSelectionMap\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
+ inputSignatures = "public static final int DOMAIN_STATE_NONE\npublic static final int DOMAIN_STATE_SELECTED\npublic static final int DOMAIN_STATE_VERIFIED\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUtils.java b/core/java/android/content/pm/verify/domain/DomainVerificationUtils.java
new file mode 100644
index 0000000..93005fa
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUtils.java
@@ -0,0 +1,181 @@
+/*
+ * 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.content.pm.verify.domain;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.util.ArraySet;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @hide
+ */
+public class DomainVerificationUtils {
+
+ private static final int STRINGS_TARGET_BYTE_SIZE = IBinder.getSuggestedMaxIpcSizeBytes() / 2;
+
+ /**
+ * Write a map containing web hosts to the given parcel, using {@link Parcel#writeBlob(byte[])}
+ * if the limit exceeds {@link IBinder#getSuggestedMaxIpcSizeBytes()} / 2. This assumes that the
+ * written map is the only data structure in the caller that varies based on the host data set.
+ * Other data that will be written to the parcel after this method will not be considered in the
+ * calculation.
+ */
+ public static void writeHostMap(@NonNull Parcel dest, @NonNull Map<String, ?> map) {
+ boolean targetSizeExceeded = false;
+ int totalSize = dest.dataSize();
+ for (String host : map.keySet()) {
+ totalSize += estimatedByteSizeOf(host);
+ if (totalSize > STRINGS_TARGET_BYTE_SIZE) {
+ targetSizeExceeded = true;
+ break;
+ }
+ }
+
+ dest.writeBoolean(targetSizeExceeded);
+
+ if (!targetSizeExceeded) {
+ dest.writeMap(map);
+ return;
+ }
+
+ Parcel data = Parcel.obtain();
+ try {
+ data.writeMap(map);
+ dest.writeBlob(data.marshall());
+ } finally {
+ data.recycle();
+ }
+ }
+
+ /**
+ * Retrieve a map previously written by {@link #writeHostMap(Parcel, Map)}.
+ */
+ @NonNull
+ @SuppressWarnings("rawtypes")
+ public static <T extends Map> T readHostMap(@NonNull Parcel in, @NonNull T map,
+ @NonNull ClassLoader classLoader) {
+ boolean targetSizeExceeded = in.readBoolean();
+
+ if (!targetSizeExceeded) {
+ in.readMap(map, classLoader);
+ return map;
+ }
+
+ Parcel data = Parcel.obtain();
+ try {
+ byte[] blob = in.readBlob();
+ data.unmarshall(blob, 0, blob.length);
+ data.setDataPosition(0);
+ data.readMap(map, classLoader);
+ } finally {
+ data.recycle();
+ }
+
+ return map;
+ }
+
+ /**
+ * {@link ArraySet} variant of {@link #writeHostMap(Parcel, Map)}.
+ */
+ public static void writeHostSet(@NonNull Parcel dest, @NonNull Set<String> set) {
+ boolean targetSizeExceeded = false;
+ int totalSize = dest.dataSize();
+ for (String host : set) {
+ totalSize += estimatedByteSizeOf(host);
+ if (totalSize > STRINGS_TARGET_BYTE_SIZE) {
+ targetSizeExceeded = true;
+ break;
+ }
+ }
+
+ dest.writeBoolean(targetSizeExceeded);
+
+ if (!targetSizeExceeded) {
+ writeSet(dest, set);
+ return;
+ }
+
+ Parcel data = Parcel.obtain();
+ try {
+ writeSet(data, set);
+ dest.writeBlob(data.marshall());
+ } finally {
+ data.recycle();
+ }
+ }
+
+ /**
+ * {@link ArraySet} variant of {@link #readHostMap(Parcel, Map, ClassLoader)}.
+ */
+ @NonNull
+ public static Set<String> readHostSet(@NonNull Parcel in) {
+ boolean targetSizeExceeded = in.readBoolean();
+
+ if (!targetSizeExceeded) {
+ return readSet(in);
+ }
+
+ Parcel data = Parcel.obtain();
+ try {
+ byte[] blob = in.readBlob();
+ data.unmarshall(blob, 0, blob.length);
+ data.setDataPosition(0);
+ return readSet(data);
+ } finally {
+ data.recycle();
+ }
+ }
+
+ private static void writeSet(@NonNull Parcel dest, @Nullable Set<String> set) {
+ if (set == null) {
+ dest.writeInt(-1);
+ return;
+ }
+ dest.writeInt(set.size());
+ for (String string : set) {
+ dest.writeString(string);
+ }
+ }
+
+ @NonNull
+ private static Set<String> readSet(@NonNull Parcel in) {
+ int size = in.readInt();
+ if (size == -1) {
+ return Collections.emptySet();
+ }
+
+ ArraySet<String> set = new ArraySet<>(size);
+ for (int count = 0; count < size; count++) {
+ set.add(in.readString());
+ }
+ return set;
+ }
+
+ /**
+ * Ballpark the size of domains to avoid unnecessary allocation of ashmem when sending domains
+ * across the client-server API.
+ */
+ public static int estimatedByteSizeOf(String string) {
+ return string.length() * 2 + 12;
+ }
+}
diff --git a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
index 21dd623b..701af32 100644
--- a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
+++ b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
@@ -16,6 +16,8 @@
package android.content.pm.verify.domain;
+import android.content.pm.verify.domain.DomainOwner;
+import android.content.pm.verify.domain.DomainSet;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationUserSelection;
import java.util.List;
@@ -35,10 +37,13 @@
DomainVerificationUserSelection getDomainVerificationUserSelection(String packageName,
int userId);
- void setDomainVerificationStatus(String domainSetId, in List<String> domains, int state);
+ @nullable
+ List<DomainOwner> getOwnersForDomain(String domain, int userId);
+
+ void setDomainVerificationStatus(String domainSetId, in DomainSet domains, int state);
void setDomainVerificationLinkHandlingAllowed(String packageName, boolean allowed, int userId);
- void setDomainVerificationUserSelection(String domainSetId, in List<String> domains,
+ void setDomainVerificationUserSelection(String domainSetId, in DomainSet domains,
boolean enabled, int userId);
}
diff --git a/core/java/android/content/pm/verify/domain/OWNERS b/core/java/android/content/pm/verify/domain/OWNERS
new file mode 100644
index 0000000..c669112
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+
+chiuwinson@google.com
+patb@google.com
+toddke@google.com
\ No newline at end of file
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 2f7aeb8..b66f048 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1956,7 +1956,7 @@
dest.writeInt(mnc);
fixUpLocaleList();
- dest.writeParcelable(mLocaleList, flags);
+ dest.writeTypedObject(mLocaleList, flags);
if(userSetLocale) {
dest.writeInt(1);
@@ -1980,7 +1980,7 @@
dest.writeInt(compatScreenWidthDp);
dest.writeInt(compatScreenHeightDp);
dest.writeInt(compatSmallestScreenWidthDp);
- dest.writeValue(windowConfiguration);
+ windowConfiguration.writeToParcel(dest, flags);
dest.writeInt(assetsSeq);
dest.writeInt(seq);
dest.writeInt(fontWeightAdjustment);
@@ -1991,7 +1991,7 @@
mcc = source.readInt();
mnc = source.readInt();
- mLocaleList = source.readParcelable(LocaleList.class.getClassLoader());
+ mLocaleList = source.readTypedObject(LocaleList.CREATOR);
locale = mLocaleList.get(0);
userSetLocale = (source.readInt()==1);
@@ -2012,7 +2012,7 @@
compatScreenWidthDp = source.readInt();
compatScreenHeightDp = source.readInt();
compatSmallestScreenWidthDp = source.readInt();
- windowConfiguration.setTo((WindowConfiguration) source.readValue(null));
+ windowConfiguration.readFromParcel(source);
assetsSeq = source.readInt();
seq = source.readInt();
fontWeightAdjustment = source.readInt();
diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java
index e512cf1..429eef9 100644
--- a/core/java/android/graphics/fonts/FontManager.java
+++ b/core/java/android/graphics/fonts/FontManager.java
@@ -20,7 +20,6 @@
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -29,7 +28,6 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.text.FontConfig;
-import android.util.Log;
import com.android.internal.graphics.fonts.IFontManager;
@@ -198,12 +196,11 @@
* @return The current font configuration. null if failed to fetch information from the system
* service.
*/
- public @Nullable FontConfig getFontConfig() {
+ public @NonNull FontConfig getFontConfig() {
try {
return mIFontManager.getFontConfig();
} catch (RemoteException e) {
- Log.e(TAG, "Failed to call getFontConfig", e);
- return null;
+ throw e.rethrowAsRuntimeException();
}
}
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index f4f9e17..e03c1f4 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
@@ -33,6 +34,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
* This class provides access to the sensor privacy services; sensor privacy allows the
@@ -42,9 +44,21 @@
*
* @hide
*/
+@SystemApi
@TestApi
@SystemService(Context.SENSOR_PRIVACY_SERVICE)
public final class SensorPrivacyManager {
+
+ /**
+ * @hide
+ */
+ public static final boolean USE_MICROPHONE_TOGGLE = true;
+
+ /**
+ * @hide
+ */
+ public static final boolean USE_CAMERA_TOGGLE = true;
+
/**
* Unique Id of this manager to identify to the service
* @hide
@@ -58,28 +72,39 @@
public static final String EXTRA_SENSOR = SensorPrivacyManager.class.getName()
+ ".extra.sensor";
- /** Microphone
- * @hide */
- @TestApi
- public static final int INDIVIDUAL_SENSOR_MICROPHONE =
- SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
-
- /** Camera
- * @hide */
- @TestApi
- public static final int INDIVIDUAL_SENSOR_CAMERA =
- SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-
/**
- * Individual sensors not listed in {@link Sensor}
+ * Individual sensors not listed in {@link Sensors}
* @hide
*/
- @IntDef(prefix = "INDIVIDUAL_SENSOR_", value = {
- INDIVIDUAL_SENSOR_MICROPHONE,
- INDIVIDUAL_SENSOR_CAMERA
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface IndividualSensor {}
+ @SystemApi
+ @TestApi
+ public static class Sensors {
+
+ private Sensors() {}
+
+ /** Microphone
+ * @hide */
+ @SystemApi
+ @TestApi
+ public static final int MICROPHONE = SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+ /** Camera
+ * @hide */
+ @SystemApi
+ @TestApi
+ public static final int CAMERA = SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+
+ /**
+ * Individual sensors not listed in {@link Sensors}
+ *
+ * @hide
+ */
+ @IntDef(value = {
+ MICROPHONE,
+ CAMERA
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Sensor {}
+ }
/**
* A class implementing this interface can register with the {@link
@@ -88,6 +113,8 @@
*
* @hide
*/
+ @SystemApi
+ @TestApi
public interface OnSensorPrivacyChangedListener {
/**
* Callback invoked when the sensor privacy state changes.
@@ -165,7 +192,8 @@
*
* @hide
*/
- public void addSensorPrivacyListener(final OnSensorPrivacyChangedListener listener) {
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@NonNull final OnSensorPrivacyChangedListener listener) {
synchronized (mListeners) {
ISensorPrivacyListener iListener = mListeners.get(listener);
if (iListener == null) {
@@ -196,15 +224,37 @@
*
* @hide
*/
- public void addSensorPrivacyListener(@IndividualSensor int sensor,
- final OnSensorPrivacyChangedListener listener) {
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@Sensors.Sensor int sensor,
+ @NonNull OnSensorPrivacyChangedListener listener) {
+ addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
+ }
+
+ /**
+ * Registers a new listener to receive notification when the state of sensor privacy
+ * changes.
+ *
+ * @param sensor the sensor to listen to changes to
+ * @param executor the executor to dispatch the callback on
+ * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
+ * privacy changes.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
+ @NonNull OnSensorPrivacyChangedListener listener) {
synchronized (mListeners) {
ISensorPrivacyListener iListener = mListeners.get(listener);
if (iListener == null) {
iListener = new ISensorPrivacyListener.Stub() {
@Override
public void onSensorPrivacyChanged(boolean enabled) {
- listener.onSensorPrivacyChanged(enabled);
+ executor.execute(() -> listener.onSensorPrivacyChanged(enabled));
}
};
mListeners.put(listener, iListener);
@@ -228,7 +278,10 @@
*
* @hide
*/
- public void removeSensorPrivacyListener(OnSensorPrivacyChangedListener listener) {
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void removeSensorPrivacyListener(@NonNull OnSensorPrivacyChangedListener listener) {
synchronized (mListeners) {
ISensorPrivacyListener iListener = mListeners.get(listener);
if (iListener != null) {
@@ -249,6 +302,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public boolean isSensorPrivacyEnabled() {
try {
return mService.isSensorPrivacyEnabled();
@@ -264,8 +318,10 @@
*
* @hide
*/
+ @SystemApi
@TestApi
- public boolean isIndividualSensorPrivacyEnabled(@IndividualSensor int sensor) {
+ @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
try {
return mService.isIndividualSensorPrivacyEnabled(mContext.getUserId(), sensor);
} catch (RemoteException e) {
@@ -283,8 +339,7 @@
*/
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
- public void setIndividualSensorPrivacy(@IndividualSensor int sensor,
- boolean enable) {
+ public void setSensorPrivacy(@Sensors.Sensor int sensor, boolean enable) {
try {
mService.setIndividualSensorPrivacy(mContext.getUserId(), sensor, enable);
} catch (RemoteException e) {
@@ -303,7 +358,7 @@
*/
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
- public void setIndividualSensorPrivacyForProfileGroup(@IndividualSensor int sensor,
+ public void setSensorPrivacyForProfileGroup(@Sensors.Sensor int sensor,
boolean enable) {
try {
mService.setIndividualSensorPrivacyForProfileGroup(mContext.getUserId(), sensor,
@@ -321,7 +376,8 @@
*
* @hide
*/
- public void suppressIndividualSensorPrivacyReminders(@NonNull String packageName,
+ @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
+ public void suppressSensorPrivacyReminders(@NonNull String packageName,
boolean suppress) {
try {
mService.suppressIndividualSensorPrivacyReminders(mContext.getUserId(), packageName,
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.aidl b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
new file mode 100644
index 0000000..e856792
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.hardware.devicestate;
+
+parcelable DeviceStateInfo;
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.java b/core/java/android/hardware/devicestate/DeviceStateInfo.java
new file mode 100644
index 0000000..bc6af37
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.java
@@ -0,0 +1,162 @@
+/*
+ * 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.hardware.devicestate;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+
+/**
+ * Information about the state of the device.
+ *
+ * @hide
+ */
+public final class DeviceStateInfo implements Parcelable {
+ /** Bit that indicates the {@link #supportedStates} field has changed. */
+ public static final int CHANGED_SUPPORTED_STATES = 1 << 0;
+
+ /** Bit that indicates the {@link #baseState} field has changed. */
+ public static final int CHANGED_BASE_STATE = 1 << 1;
+
+ /** Bit that indicates the {@link #currentState} field has changed. */
+ public static final int CHANGED_CURRENT_STATE = 1 << 2;
+
+ @IntDef(prefix = {"CHANGED_"}, flag = true, value = {
+ CHANGED_SUPPORTED_STATES,
+ CHANGED_BASE_STATE,
+ CHANGED_CURRENT_STATE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ChangeFlags {}
+
+ /**
+ * The list of states supported by the device.
+ */
+ @NonNull
+ public final int[] supportedStates;
+
+ /**
+ * The base (non-override) state of the device. The base state is the state of the device
+ * ignoring any override requests made through a call to {@link DeviceStateManager#requestState(
+ * DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+ */
+ public final int baseState;
+
+ /**
+ * The state of the device.
+ */
+ public final int currentState;
+
+ /**
+ * Creates a new instance of {@link DeviceStateInfo}.
+ * <p>
+ * NOTE: Unlike {@link #DeviceStateInfo(DeviceStateInfo)}, this constructor does not copy the
+ * supplied parameters.
+ */
+ public DeviceStateInfo(@NonNull int[] supportedStates, int baseState, int state) {
+ this.supportedStates = supportedStates;
+ this.baseState = baseState;
+ this.currentState = state;
+ }
+
+ /**
+ * Creates a new instance of {@link DeviceStateInfo} copying the fields of {@code info} into
+ * the fields of the returned instance.
+ */
+ public DeviceStateInfo(@NonNull DeviceStateInfo info) {
+ this(Arrays.copyOf(info.supportedStates, info.supportedStates.length),
+ info.baseState, info.currentState);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (this == other) return true;
+ if (other == null || getClass() != other.getClass()) return false;
+ DeviceStateInfo that = (DeviceStateInfo) other;
+ return baseState == that.baseState
+ && currentState == that.currentState
+ && Arrays.equals(supportedStates, that.supportedStates);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(baseState, currentState);
+ result = 31 * result + Arrays.hashCode(supportedStates);
+ return result;
+ }
+
+ /** Returns a bitmask of the differences between this instance and {@code other}. */
+ @ChangeFlags
+ public int diff(@NonNull DeviceStateInfo other) {
+ int diff = 0;
+ if (!Arrays.equals(supportedStates, other.supportedStates)) {
+ diff |= CHANGED_SUPPORTED_STATES;
+ }
+ if (baseState != other.baseState) {
+ diff |= CHANGED_BASE_STATE;
+ }
+ if (currentState != other.currentState) {
+ diff |= CHANGED_CURRENT_STATE;
+ }
+ return diff;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(supportedStates.length);
+ for (int i = 0; i < supportedStates.length; i++) {
+ dest.writeInt(supportedStates[i]);
+ }
+
+ dest.writeInt(baseState);
+ dest.writeInt(currentState);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<DeviceStateInfo>() {
+ @Override
+ public DeviceStateInfo createFromParcel(Parcel source) {
+ final int numberOfSupportedStates = source.readInt();
+ final int[] supportedStates = new int[numberOfSupportedStates];
+ for (int i = 0; i < numberOfSupportedStates; i++) {
+ supportedStates[i] = source.readInt();
+ }
+ final int baseState = source.readInt();
+ final int currentState = source.readInt();
+
+ return new DeviceStateInfo(supportedStates, baseState, currentState);
+ }
+
+ @Override
+ public DeviceStateInfo[] newArray(int size) {
+ return new DeviceStateInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index 2d4b2cc..250145e 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -111,38 +111,63 @@
}
/**
- * Registers a listener to receive notifications about changes in device state.
+ * Registers a callback to receive notifications about changes in device state.
*
* @param executor the executor to process notifications.
- * @param listener the listener to register.
+ * @param callback the callback to register.
*
- * @see DeviceStateListener
+ * @see DeviceStateCallback
*/
- public void addDeviceStateListener(@NonNull @CallbackExecutor Executor executor,
- @NonNull DeviceStateListener listener) {
- mGlobal.registerDeviceStateListener(listener, executor);
+ public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull DeviceStateCallback callback) {
+ mGlobal.registerDeviceStateCallback(callback, executor);
}
/**
- * Unregisters a listener previously registered with
- * {@link #addDeviceStateListener(Executor, DeviceStateListener)}.
+ * Unregisters a callback previously registered with
+ * {@link #registerCallback(Executor, DeviceStateCallback)}.
*/
- public void removeDeviceStateListener(@NonNull DeviceStateListener listener) {
- mGlobal.unregisterDeviceStateListener(listener);
+ public void unregisterCallback(@NonNull DeviceStateCallback callback) {
+ mGlobal.unregisterDeviceStateCallback(callback);
}
- /**
- * Listens for changes in device states.
- */
- public interface DeviceStateListener {
+ /** Callback to receive notifications about changes in device state. */
+ public interface DeviceStateCallback {
+ /**
+ * Called in response to a change in the states supported by the device.
+ * <p>
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in the supported states.
+ *
+ * @param supportedStates the new supported states.
+ *
+ * @see DeviceStateManager#getSupportedStates()
+ */
+ default void onSupportedStatesChanged(@NonNull int[] supportedStates) {}
+
+ /**
+ * Called in response to a change in the base device state.
+ * <p>
+ * The base state is the state of the device without considering any requests made through
+ * calls to {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}
+ * from any client process. The base state is guaranteed to match the state provided with a
+ * call to {@link #onStateChanged(int)} when there are no active requests from any process.
+ * <p>
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in the non-override state.
+ *
+ * @param state the new base device state.
+ */
+ default void onBaseStateChanged(int state) {}
+
/**
* Called in response to device state changes.
* <p>
- * Guaranteed to be called once on registration of the listener with the
- * initial value and then on every subsequent change in device state.
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in device state.
*
- * @param deviceState the new device state.
+ * @param state the new device state.
*/
- void onDeviceStateChanged(int deviceState);
+ void onStateChanged(int state);
}
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index b9ae88e..1b37fb9 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.devicestate.DeviceStateManager.DeviceStateListener;
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -31,12 +31,14 @@
import com.android.internal.annotations.VisibleForTesting.Visibility;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.concurrent.Executor;
/**
* Provides communication with the device state system service on behalf of applications.
*
* @see DeviceStateManager
+ *
* @hide
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
@@ -68,13 +70,13 @@
private DeviceStateManagerCallback mCallback;
@GuardedBy("mLock")
- private final ArrayList<DeviceStateListenerWrapper> mListeners = new ArrayList<>();
+ private final ArrayList<DeviceStateCallbackWrapper> mCallbacks = new ArrayList<>();
@GuardedBy("mLock")
private final ArrayMap<IBinder, DeviceStateRequestWrapper> mRequests = new ArrayMap<>();
@Nullable
@GuardedBy("mLock")
- private Integer mLastReceivedState;
+ private DeviceStateInfo mLastReceivedInfo;
@VisibleForTesting
public DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
@@ -87,18 +89,31 @@
* @see DeviceStateManager#getSupportedStates()
*/
public int[] getSupportedStates() {
- try {
- return mDeviceStateManager.getSupportedDeviceStates();
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
+ synchronized (mLock) {
+ final DeviceStateInfo currentInfo;
+ if (mLastReceivedInfo != null) {
+ // If we have mLastReceivedInfo a callback is registered for this instance and it
+ // is receiving the most recent info from the server. Use that info here.
+ currentInfo = mLastReceivedInfo;
+ } else {
+ // If mLastReceivedInfo is null there is no registered callback so we manually
+ // fetch the current info.
+ try {
+ currentInfo = mDeviceStateManager.getDeviceStateInfo();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ return Arrays.copyOf(currentInfo.supportedStates, currentInfo.supportedStates.length);
}
}
/**
* Submits a {@link DeviceStateRequest request} to modify the device state.
*
- * @see DeviceStateManager#requestState(DeviceStateRequest,
- * Executor, DeviceStateRequest.Callback)
+ * @see DeviceStateManager#requestState(DeviceStateRequest, Executor,
+ * DeviceStateRequest.Callback)
* @see DeviceStateRequest
*/
public void requestState(@NonNull DeviceStateRequest request,
@@ -157,49 +172,56 @@
}
/**
- * Registers a listener to receive notifications about changes in device state.
+ * Registers a callback to receive notifications about changes in device state.
*
- * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+ * @see DeviceStateManager#registerCallback(Executor, DeviceStateCallback)
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
- public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
+ public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
@NonNull Executor executor) {
- Integer stateToReport;
- DeviceStateListenerWrapper wrapper;
+ DeviceStateCallbackWrapper wrapper;
+ DeviceStateInfo currentInfo;
synchronized (mLock) {
- registerCallbackIfNeededLocked();
-
- int index = findListenerLocked(listener);
+ int index = findCallbackLocked(callback);
if (index != -1) {
- // This listener is already registered.
+ // This callback is already registered.
return;
}
- wrapper = new DeviceStateListenerWrapper(listener, executor);
- mListeners.add(wrapper);
- stateToReport = mLastReceivedState;
+ registerCallbackIfNeededLocked();
+ if (mLastReceivedInfo == null) {
+ // Initialize the last received info with the current info if this is the first
+ // callback being registered.
+ try {
+ mLastReceivedInfo = mDeviceStateManager.getDeviceStateInfo();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ currentInfo = new DeviceStateInfo(mLastReceivedInfo);
+
+ wrapper = new DeviceStateCallbackWrapper(callback, executor);
+ mCallbacks.add(wrapper);
}
- if (stateToReport != null) {
- // Notify the listener with the most recent device state from the server. If the state
- // to report is null this is likely the first listener added and we're still waiting
- // from the callback from the server.
- wrapper.notifyDeviceStateChanged(stateToReport);
- }
+ wrapper.notifySupportedStatesChanged(currentInfo.supportedStates);
+ wrapper.notifyBaseStateChanged(currentInfo.baseState);
+ wrapper.notifyStateChanged(currentInfo.currentState);
}
/**
- * Unregisters a listener previously registered with
- * {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
+ * Unregisters a callback previously registered with
+ * {@link #registerDeviceStateCallback(DeviceStateCallback, Executor)}}.
*
- * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+ * @see DeviceStateManager#unregisterCallback(DeviceStateCallback)
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
- public void unregisterDeviceStateListener(DeviceStateListener listener) {
+ public void unregisterDeviceStateCallback(@NonNull DeviceStateCallback callback) {
synchronized (mLock) {
- int indexToRemove = findListenerLocked(listener);
+ int indexToRemove = findCallbackLocked(callback);
if (indexToRemove != -1) {
- mListeners.remove(indexToRemove);
+ mCallbacks.remove(indexToRemove);
}
}
}
@@ -210,14 +232,15 @@
try {
mDeviceStateManager.registerCallback(mCallback);
} catch (RemoteException ex) {
+ mCallback = null;
throw ex.rethrowFromSystemServer();
}
}
}
- private int findListenerLocked(DeviceStateListener listener) {
- for (int i = 0; i < mListeners.size(); i++) {
- if (mListeners.get(i).mDeviceStateListener.equals(listener)) {
+ private int findCallbackLocked(DeviceStateCallback callback) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ if (mCallbacks.get(i).mDeviceStateCallback.equals(callback)) {
return i;
}
}
@@ -234,16 +257,34 @@
return null;
}
- /** Handles a call from the server that the device state has changed. */
- private void handleDeviceStateChanged(int newDeviceState) {
- ArrayList<DeviceStateListenerWrapper> listeners;
+ /** Handles a call from the server that the device state info has changed. */
+ private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
+ ArrayList<DeviceStateCallbackWrapper> callbacks;
+ DeviceStateInfo oldInfo;
synchronized (mLock) {
- mLastReceivedState = newDeviceState;
- listeners = new ArrayList<>(mListeners);
+ oldInfo = mLastReceivedInfo;
+ mLastReceivedInfo = info;
+ callbacks = new ArrayList<>(mCallbacks);
}
- for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).notifyDeviceStateChanged(newDeviceState);
+ final int diff = oldInfo == null ? 1 : info.diff(oldInfo);
+ if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ // Copy the array to prevent callbacks from modifying the internal state.
+ final int[] supportedStates = Arrays.copyOf(info.supportedStates,
+ info.supportedStates.length);
+ callbacks.get(i).notifySupportedStatesChanged(supportedStates);
+ }
+ }
+ if ((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ callbacks.get(i).notifyBaseStateChanged(info.baseState);
+ }
+ }
+ if ((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ callbacks.get(i).notifyStateChanged(info.currentState);
+ }
}
}
@@ -291,8 +332,8 @@
private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
@Override
- public void onDeviceStateChanged(int deviceState) {
- handleDeviceStateChanged(deviceState);
+ public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+ handleDeviceStateInfoChanged(info);
}
@Override
@@ -311,17 +352,29 @@
}
}
- private static final class DeviceStateListenerWrapper {
- private final DeviceStateListener mDeviceStateListener;
+ private static final class DeviceStateCallbackWrapper {
+ @NonNull
+ private final DeviceStateCallback mDeviceStateCallback;
+ @NonNull
private final Executor mExecutor;
- DeviceStateListenerWrapper(DeviceStateListener listener, Executor executor) {
- mDeviceStateListener = listener;
+ DeviceStateCallbackWrapper(@NonNull DeviceStateCallback callback,
+ @NonNull Executor executor) {
+ mDeviceStateCallback = callback;
mExecutor = executor;
}
- void notifyDeviceStateChanged(int newDeviceState) {
- mExecutor.execute(() -> mDeviceStateListener.onDeviceStateChanged(newDeviceState));
+ void notifySupportedStatesChanged(int[] newSupportedStates) {
+ mExecutor.execute(() ->
+ mDeviceStateCallback.onSupportedStatesChanged(newSupportedStates));
+ }
+
+ void notifyBaseStateChanged(int newBaseState) {
+ mExecutor.execute(() -> mDeviceStateCallback.onBaseStateChanged(newBaseState));
+ }
+
+ void notifyStateChanged(int newDeviceState) {
+ mExecutor.execute(() -> mDeviceStateCallback.onStateChanged(newDeviceState));
}
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateRequest.java b/core/java/android/hardware/devicestate/DeviceStateRequest.java
index 70f7002..df488d2 100644
--- a/core/java/android/hardware/devicestate/DeviceStateRequest.java
+++ b/core/java/android/hardware/devicestate/DeviceStateRequest.java
@@ -116,7 +116,7 @@
* requested state.
* <p>
* Guaranteed to be called after a call to
- * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)} with a state
+ * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} with a state
* matching the requested state.
*/
default void onRequestActivated(@NonNull DeviceStateRequest request) {}
@@ -125,7 +125,7 @@
* Called to indicate the request has been temporarily suspended.
* <p>
* Guaranteed to be called before a call to
- * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+ * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
*/
default void onRequestSuspended(@NonNull DeviceStateRequest request) {}
@@ -135,7 +135,7 @@
* DeviceStateRequest.Callback)}.
* <p>
* Guaranteed to be called before a call to
- * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+ * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
* <p>
* Note: A call to {@link #onRequestSuspended(DeviceStateRequest)} is not guaranteed to
* occur before this method.
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
index 323ad21..14ed03d 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -16,25 +16,26 @@
package android.hardware.devicestate;
+import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.IDeviceStateManagerCallback;
/** @hide */
interface IDeviceStateManager {
+ /** Returns the current device state info. */
+ DeviceStateInfo getDeviceStateInfo();
+
/**
* Registers a callback to receive notifications from the device state manager. Only one
* callback can be registered per-process.
* <p>
* As the callback mechanism is used to alert the caller of changes to request status a callback
* <b>MUST</b> be registered before calling {@link #requestState(IBinder, int, int)} or
- * {@link #cancelRequest(IBinder)}. Otherwise an exception will be thrown.
+ * {@link #cancelRequest(IBinder)}, otherwise an exception will be thrown.
*
* @throws SecurityException if a callback is already registered for the calling process.
*/
void registerCallback(in IDeviceStateManagerCallback callback);
- /** Returns the array of supported device state identifiers. */
- int[] getSupportedDeviceStates();
-
/**
* Requests that the device enter the supplied {@code state}. A callback <b>MUST</b> have been
* previously registered with {@link #registerCallback(IDeviceStateManagerCallback)} before a
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
index ee2a071..593be86 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
@@ -16,20 +16,23 @@
package android.hardware.devicestate;
+import android.hardware.devicestate.DeviceStateInfo;
+
/** @hide */
interface IDeviceStateManagerCallback {
/**
- * Called in response to a change in device state. Guaranteed to be called once with the initial
- * value on registration of the callback.
+ * Called in response to a change in {@link DeviceStateInfo}.
*
- * @param deviceState the new state of the device.
+ * @param info the new device state info.
+ *
+ * @see DeviceStateInfo
*/
- oneway void onDeviceStateChanged(int deviceState);
+ oneway void onDeviceStateInfoChanged(in DeviceStateInfo info);
/**
* Called to notify the callback that a request has become active. Guaranteed to be called
- * after a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming active
- * resulted in a device state change.
+ * after a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+ * becoming active resulted in a change of device state info.
*
* @param token the request token previously registered with
* {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -38,8 +41,8 @@
/**
* Called to notify the callback that a request has become suspended. Guaranteed to be called
- * before a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming
- * suspended resulted in a device state change.
+ * before a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+ * becoming suspended resulted in a change of device state info.
*
* @param token the request token previously registered with
* {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -49,8 +52,8 @@
/**
* Called to notify the callback that a request has become canceled. No further callbacks will
* be triggered for this request. Guaranteed to be called before a subsequent call to
- * {@link #onDeviceStateChanged(int)} if the request becoming canceled resulted in a device
- * state change.
+ * {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request becoming canceled resulted
+ * in a change of device state info.
*
* @param token the request token previously registered with
* {@link IDeviceStateManager#requestState(IBinder, int, int)}
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 41126b7..9457d8f1 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -16,40 +16,69 @@
package android.hardware.display;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Product-specific information about the display or the directly connected device on the
* display chain. For example, if the display is transitively connected, this field may contain
* product information about the intermediate device.
- * @hide
*/
public final class DeviceProductInfo implements Parcelable {
+ /** @hide */
+ @IntDef(prefix = {"CONNECTION_TO_SINK_"}, value = {
+ CONNECTION_TO_SINK_UNKNOWN,
+ CONNECTION_TO_SINK_BUILT_IN,
+ CONNECTION_TO_SINK_DIRECT,
+ CONNECTION_TO_SINK_TRANSITIVE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ConnectionToSinkType { }
+
+ /** The device connection to the display sink is unknown. */
+ public static final int CONNECTION_TO_SINK_UNKNOWN =
+ IDeviceProductInfoConstants.CONNECTION_TO_SINK_UNKNOWN;
+
+ /** The display sink is built-in to the device */
+ public static final int CONNECTION_TO_SINK_BUILT_IN =
+ IDeviceProductInfoConstants.CONNECTION_TO_SINK_BUILT_IN;
+
+ /** The device is directly connected to the display sink. */
+ public static final int CONNECTION_TO_SINK_DIRECT =
+ IDeviceProductInfoConstants.CONNECTION_TO_SINK_DIRECT;
+
+ /** The device is transitively connected to the display sink. */
+ public static final int CONNECTION_TO_SINK_TRANSITIVE =
+ IDeviceProductInfoConstants.CONNECTION_TO_SINK_TRANSITIVE;
+
private final String mName;
private final String mManufacturerPnpId;
private final String mProductId;
private final Integer mModelYear;
private final ManufactureDate mManufactureDate;
- private final int[] mRelativeAddress;
+ private final @ConnectionToSinkType int mConnectionToSinkType;
+ /** @hide */
public DeviceProductInfo(
String name,
String manufacturerPnpId,
String productId,
Integer modelYear,
ManufactureDate manufactureDate,
- int[] relativeAddress) {
+ int connectionToSinkType) {
this.mName = name;
this.mManufacturerPnpId = manufacturerPnpId;
this.mProductId = productId;
this.mModelYear = modelYear;
this.mManufactureDate = manufactureDate;
- this.mRelativeAddress = relativeAddress;
+ this.mConnectionToSinkType = connectionToSinkType;
}
private DeviceProductInfo(Parcel in) {
@@ -58,12 +87,13 @@
mProductId = (String) in.readValue(null);
mModelYear = (Integer) in.readValue(null);
mManufactureDate = (ManufactureDate) in.readValue(null);
- mRelativeAddress = in.createIntArray();
+ mConnectionToSinkType = in.readInt();
}
/**
* @return Display name.
*/
+ @Nullable
public String getName() {
return mName;
}
@@ -71,6 +101,7 @@
/**
* @return Manufacturer Plug and Play ID.
*/
+ @NonNull
public String getManufacturerPnpId() {
return mManufacturerPnpId;
}
@@ -78,32 +109,58 @@
/**
* @return Manufacturer product ID.
*/
+ @NonNull
public String getProductId() {
return mProductId;
}
/**
- * @return Model year of the device. Typically exactly one of model year or
- * manufacture date will be present.
+ * @return Model year of the device. Return -1 if not available. Typically,
+ * one of model year or manufacture year is available.
*/
- public Integer getModelYear() {
- return mModelYear;
+ public int getModelYear() {
+ return mModelYear != null ? mModelYear : -1;
+ }
+
+ /**
+ * @return The year of manufacture, or -1 it is not available. Typically,
+ * one of model year or manufacture year is available.
+ */
+ public int getManufactureYear() {
+ if (mManufactureDate == null) {
+ return -1;
+ }
+ return mManufactureDate.mYear != null ? mManufactureDate.mYear : -1;
+ }
+
+ /**
+ * @return The week of manufacture, or -1 it is not available. Typically,
+ * not present if model year is available.
+ */
+ public int getManufactureWeek() {
+ if (mManufactureDate == null) {
+ return -1;
+ }
+ return mManufactureDate.mWeek != null ? mManufactureDate.mWeek : -1;
}
/**
* @return Manufacture date. Typically exactly one of model year or manufacture
* date will be present.
+ *
+ * @hide
*/
public ManufactureDate getManufactureDate() {
return mManufactureDate;
}
/**
- * @return Relative address in the display network. For example, for HDMI connected devices this
- * can be its physical address. Each component of the address is in the range [0, 255].
+ * @return How the current device is connected to the display sink. For example, the display
+ * can be connected immediately to the device or there can be a receiver in between.
*/
- public int[] getRelativeAddress() {
- return mRelativeAddress;
+ @ConnectionToSinkType
+ public int getConnectionToSinkType() {
+ return mConnectionToSinkType;
}
@Override
@@ -119,8 +176,8 @@
+ mModelYear
+ ", manufactureDate="
+ mManufactureDate
- + ", relativeAddress="
- + Arrays.toString(mRelativeAddress)
+ + ", connectionToSinkType="
+ + mConnectionToSinkType
+ '}';
}
@@ -134,16 +191,16 @@
&& Objects.equals(mProductId, that.mProductId)
&& Objects.equals(mModelYear, that.mModelYear)
&& Objects.equals(mManufactureDate, that.mManufactureDate)
- && Arrays.equals(mRelativeAddress, that.mRelativeAddress);
+ && mConnectionToSinkType == that.mConnectionToSinkType;
}
@Override
public int hashCode() {
return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate,
- Arrays.hashCode(mRelativeAddress));
+ mConnectionToSinkType);
}
- public static final Creator<DeviceProductInfo> CREATOR =
+ @NonNull public static final Creator<DeviceProductInfo> CREATOR =
new Creator<DeviceProductInfo>() {
@Override
public DeviceProductInfo createFromParcel(Parcel in) {
@@ -162,13 +219,13 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mName);
dest.writeString(mManufacturerPnpId);
dest.writeValue(mProductId);
dest.writeValue(mModelYear);
dest.writeValue(mManufactureDate);
- dest.writeIntArray(mRelativeAddress);
+ dest.writeInt(mConnectionToSinkType);
}
/**
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index f868a50..0256b7b 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -1448,13 +1448,17 @@
case FACE_ACQUIRED_TOO_FAR:
return context.getString(R.string.face_acquired_too_far);
case FACE_ACQUIRED_TOO_HIGH:
- return context.getString(R.string.face_acquired_too_high);
- case FACE_ACQUIRED_TOO_LOW:
+ // TODO(b/181269243): Change back once error codes are fixed.
return context.getString(R.string.face_acquired_too_low);
+ case FACE_ACQUIRED_TOO_LOW:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_high);
case FACE_ACQUIRED_TOO_RIGHT:
- return context.getString(R.string.face_acquired_too_right);
- case FACE_ACQUIRED_TOO_LEFT:
+ // TODO(b/181269243) Change back once error codes are fixed.
return context.getString(R.string.face_acquired_too_left);
+ case FACE_ACQUIRED_TOO_LEFT:
+ // TODO(b/181269243) Change back once error codes are fixed.
+ return context.getString(R.string.face_acquired_too_right);
case FACE_ACQUIRED_POOR_GAZE:
return context.getString(R.string.face_acquired_poor_gaze);
case FACE_ACQUIRED_NOT_DETECTED:
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index 663a704..51addc9 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -85,8 +85,8 @@
boolean resetLockoutRequiresHardwareAuthToken) {
// TODO(b/179175438): Value should be provided from the HAL
this(sensorId, strength, maxEnrollmentsPerUser, sensorType,
- resetLockoutRequiresHardwareAuthToken, 0 /* sensorLocationX */,
- 0 /* sensorLocationY */, 0 /* sensorRadius */);
+ resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
+ 1636 /* sensorLocationY */, 130 /* sensorRadius */);
}
/**
diff --git a/core/java/android/hardware/soundtrigger/OWNERS b/core/java/android/hardware/soundtrigger/OWNERS
index 816bc6b..e5d0370 100644
--- a/core/java/android/hardware/soundtrigger/OWNERS
+++ b/core/java/android/hardware/soundtrigger/OWNERS
@@ -1 +1,2 @@
-include /core/java/android/media/soundtrigger/OWNERS
+ytai@google.com
+elaurent@google.com
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 9198eb7..5cfcd66 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -171,7 +171,7 @@
SomeArgs args = (SomeArgs) msg.obj;
try {
inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
- (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3);
+ (IInputMethodPrivilegedOperations) args.arg2);
} finally {
args.recycle();
}
@@ -280,10 +280,9 @@
@BinderThread
@Override
public void initializeInternal(IBinder token, int displayId,
- IInputMethodPrivilegedOperations privOps, int configChanges) {
+ IInputMethodPrivilegedOperations privOps) {
mCaller.executeOrSendMessage(
- mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps,
- configChanges));
+ mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
}
@BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 03dd306..7e2be01 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,7 +70,6 @@
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -132,7 +131,6 @@
import android.window.WindowMetricsHelper;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
@@ -515,8 +513,6 @@
private boolean mIsAutomotive;
private Handler mHandler;
private boolean mImeSurfaceScheduledForRemoval;
- private Configuration mLastKnownConfig;
- private int mHandledConfigChanges;
/**
* An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
@@ -592,14 +588,12 @@
@MainThread
@Override
public final void initializeInternal(@NonNull IBinder token, int displayId,
- IInputMethodPrivilegedOperations privilegedOperations,
- int configChanges) {
+ IInputMethodPrivilegedOperations privilegedOperations) {
if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
Log.w(TAG, "The token has already registered, ignore this initialization.");
return;
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
- mHandledConfigChanges = configChanges;
mPrivOps.set(privilegedOperations);
InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
updateInputMethodDisplay(displayId);
@@ -827,9 +821,6 @@
setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
}
final boolean isVisible = isInputViewShown();
- if (isVisible && getResources() != null) {
- mLastKnownConfig = getResources().getConfiguration();
- }
final boolean visibilityChanged = isVisible != wasVisible;
if (resultReceiver != null) {
resultReceiver.send(visibilityChanged
@@ -1437,37 +1428,10 @@
* state: {@link #onStartInput} if input is active, and
* {@link #onCreateInputView} and {@link #onStartInputView} and related
* appropriate functions if the UI is displayed.
- * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration
- * changes themselves instead of being restarted with
- * {@link android.R.styleable#InputMethod_configChanges}.
*/
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- if (shouldImeRestartForConfig(newConfig)) {
- resetStateForNewConfiguration();
- }
- }
-
- /**
- * @return {@code true} if {@link InputMethodService} needs to restart to handle
- * .{@link #onConfigurationChanged(Configuration)}
- */
- @VisibleForTesting
- boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) {
- if (mLastKnownConfig == null) {
- return true;
- }
- // If the new config is the same as the config this Service is already running with,
- // then don't bother calling resetStateForNewConfiguration.
- int diff = mLastKnownConfig.diffPublicOnly(newConfig);
- if (diff != 0) {
- // remove attrs not-relevant to IME service.
- diff &= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
- diff &= ActivityInfo.CONFIG_KEYBOARD;
- diff &= ActivityInfo.CONFIG_NAVIGATION;
- }
- int unhandledDiff = (diff & ~mHandledConfigChanges);
- return unhandledDiff != 0;
+ resetStateForNewConfiguration();
}
private void resetStateForNewConfiguration() {
@@ -3217,17 +3181,7 @@
requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
}
}
-
- @VisibleForTesting
- void setLastKnownConfig(@NonNull Configuration config) {
- mLastKnownConfig = config;
- }
-
- @VisibleForTesting
- void setHandledConfigChanges(int configChanges) {
- mHandledConfigChanges = configChanges;
- }
-
+
void startExtractingText(boolean inputChanged) {
final ExtractEditText eet = mExtractEditText;
if (eet != null && getCurrentInputStarted()
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 32b19a4..303a407 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -18,6 +18,7 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.wifi.WifiInfo;
@@ -41,6 +42,22 @@
public static final int SUBTYPE_COMBINED = -1;
+ /**
+ * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}.
+ * @hide
+ */
+ public static final int OEM_NONE = 0x0;
+ /**
+ * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}.
+ * @hide
+ */
+ public static final int OEM_PAID = 0x1;
+ /**
+ * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}.
+ * @hide
+ */
+ public static final int OEM_PRIVATE = 0x2;
+
final int mType;
final int mSubType;
final String mSubscriberId;
@@ -48,10 +65,11 @@
final boolean mRoaming;
final boolean mMetered;
final boolean mDefaultNetwork;
+ final int mOemManaged;
public NetworkIdentity(
int type, int subType, String subscriberId, String networkId, boolean roaming,
- boolean metered, boolean defaultNetwork) {
+ boolean metered, boolean defaultNetwork, int oemManaged) {
mType = type;
mSubType = subType;
mSubscriberId = subscriberId;
@@ -59,12 +77,13 @@
mRoaming = roaming;
mMetered = metered;
mDefaultNetwork = defaultNetwork;
+ mOemManaged = oemManaged;
}
@Override
public int hashCode() {
return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered,
- mDefaultNetwork);
+ mDefaultNetwork, mOemManaged);
}
@Override
@@ -75,7 +94,8 @@
&& Objects.equals(mSubscriberId, ident.mSubscriberId)
&& Objects.equals(mNetworkId, ident.mNetworkId)
&& mMetered == ident.mMetered
- && mDefaultNetwork == ident.mDefaultNetwork;
+ && mDefaultNetwork == ident.mDefaultNetwork
+ && mOemManaged == ident.mOemManaged;
}
return false;
}
@@ -102,6 +122,8 @@
}
builder.append(", metered=").append(mMetered);
builder.append(", defaultNetwork=").append(mDefaultNetwork);
+ // TODO(180557699): Print a human readable string for OEM managed state.
+ builder.append(", oemManaged=").append(mOemManaged);
return builder.append("}").toString();
}
@@ -120,6 +142,7 @@
proto.write(NetworkIdentityProto.ROAMING, mRoaming);
proto.write(NetworkIdentityProto.METERED, mMetered);
proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
+ proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged);
proto.end(start);
}
@@ -152,6 +175,10 @@
return mDefaultNetwork;
}
+ public int getOemManaged() {
+ return mOemManaged;
+ }
+
/**
* Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
* assuming that any mobile networks are using the current IMSI. The subType if applicable,
@@ -171,6 +198,8 @@
subscriberId = state.subscriberId;
+ final int oemManaged = getOemBitfield(state.networkCapabilities);
+
if (legacyType == TYPE_WIFI) {
if (state.networkCapabilities.getSsid() != null) {
networkId = state.networkCapabilities.getSsid();
@@ -185,7 +214,24 @@
}
return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered,
- defaultNetwork);
+ defaultNetwork, oemManaged);
+ }
+
+ /**
+ * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}.
+ * @hide
+ */
+ public static int getOemBitfield(NetworkCapabilities nc) {
+ int oemManaged = OEM_NONE;
+
+ if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) {
+ oemManaged |= OEM_PAID;
+ }
+ if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) {
+ oemManaged |= OEM_PRIVATE;
+ }
+
+ return oemManaged;
}
@Override
@@ -209,6 +255,9 @@
if (res == 0) {
res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork);
}
+ if (res == 0) {
+ res = Integer.compare(mOemManaged, another.mOemManaged);
+ }
return res;
}
}
diff --git a/core/java/android/net/NetworkStateSnapshot.aidl b/core/java/android/net/NetworkStateSnapshot.aidl
new file mode 100644
index 0000000..cb602d79
--- /dev/null
+++ b/core/java/android/net/NetworkStateSnapshot.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.net;
+
+parcelable NetworkStateSnapshot;
diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java
new file mode 100644
index 0000000..881b373
--- /dev/null
+++ b/core/java/android/net/NetworkStateSnapshot.java
@@ -0,0 +1,106 @@
+/*
+ * 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.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Snapshot of network state.
+ *
+ * @hide
+ */
+public final class NetworkStateSnapshot implements Parcelable {
+ @NonNull
+ public final LinkProperties linkProperties;
+ @NonNull
+ public final NetworkCapabilities networkCapabilities;
+ @NonNull
+ public final Network network;
+ @Nullable
+ public final String subscriberId;
+ public final int legacyType;
+
+ public NetworkStateSnapshot(@NonNull LinkProperties linkProperties,
+ @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+ @Nullable String subscriberId, int legacyType) {
+ this.linkProperties = Objects.requireNonNull(linkProperties);
+ this.networkCapabilities = Objects.requireNonNull(networkCapabilities);
+ this.network = Objects.requireNonNull(network);
+ this.subscriberId = subscriberId;
+ this.legacyType = legacyType;
+ }
+
+ public NetworkStateSnapshot(@NonNull Parcel in) {
+ linkProperties = in.readParcelable(null);
+ networkCapabilities = in.readParcelable(null);
+ network = in.readParcelable(null);
+ subscriberId = in.readString();
+ legacyType = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeParcelable(linkProperties, flags);
+ out.writeParcelable(networkCapabilities, flags);
+ out.writeParcelable(network, flags);
+ out.writeString(subscriberId);
+ out.writeInt(legacyType);
+ }
+
+ @NonNull
+ public static final Creator<NetworkStateSnapshot> CREATOR =
+ new Creator<NetworkStateSnapshot>() {
+ @NonNull
+ @Override
+ public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) {
+ return new NetworkStateSnapshot(in);
+ }
+
+ @NonNull
+ @Override
+ public NetworkStateSnapshot[] newArray(int size) {
+ return new NetworkStateSnapshot[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof NetworkStateSnapshot)) return false;
+ NetworkStateSnapshot that = (NetworkStateSnapshot) o;
+ return legacyType == that.legacyType
+ && Objects.equals(linkProperties, that.linkProperties)
+ && Objects.equals(networkCapabilities, that.networkCapabilities)
+ && Objects.equals(network, that.network)
+ && Objects.equals(subscriberId, that.subscriberId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(linkProperties, networkCapabilities, network, subscriberId, legacyType);
+ }
+}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index aa61e03..c83dd99 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -23,6 +23,7 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.NetworkIdentity.OEM_NONE;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -99,6 +100,22 @@
*/
public static final int NETWORK_TYPE_5G_NSA = -2;
+ /**
+ * Value to match both OEM managed and unmanaged networks (all networks).
+ * @hide
+ */
+ public static final int OEM_MANAGED_ALL = -1;
+ /**
+ * Value to match networks which are not OEM managed.
+ * @hide
+ */
+ public static final int OEM_MANAGED_NO = OEM_NONE;
+ /**
+ * Value to match any OEM managed network.
+ * @hide
+ */
+ public static final int OEM_MANAGED_YES = -2;
+
private static boolean isKnownMatchRule(final int rule) {
switch (rule) {
case MATCH_MOBILE:
@@ -151,10 +168,10 @@
@NetworkType int ratType) {
if (TextUtils.isEmpty(subscriberId)) {
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
}
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
}
/**
@@ -235,6 +252,9 @@
private final int mDefaultNetwork;
private final int mSubType;
+ // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
+ private final int mOemManaged;
+
@UnsupportedAppUsage
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
@@ -243,11 +263,12 @@
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId) {
this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL);
+ DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
}
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String networkId, int metered, int roaming, int defaultNetwork, int subType) {
+ String networkId, int metered, int roaming, int defaultNetwork, int subType,
+ int oemManaged) {
mMatchRule = matchRule;
mSubscriberId = subscriberId;
mMatchSubscriberIds = matchSubscriberIds;
@@ -256,6 +277,7 @@
mRoaming = roaming;
mDefaultNetwork = defaultNetwork;
mSubType = subType;
+ mOemManaged = oemManaged;
if (!isKnownMatchRule(matchRule)) {
Log.e(TAG, "Unknown network template rule " + matchRule
@@ -272,6 +294,7 @@
mRoaming = in.readInt();
mDefaultNetwork = in.readInt();
mSubType = in.readInt();
+ mOemManaged = in.readInt();
}
@Override
@@ -284,6 +307,7 @@
dest.writeInt(mRoaming);
dest.writeInt(mDefaultNetwork);
dest.writeInt(mSubType);
+ dest.writeInt(mOemManaged);
}
@Override
@@ -319,13 +343,16 @@
if (mSubType != NETWORK_TYPE_ALL) {
builder.append(", subType=").append(mSubType);
}
+ if (mOemManaged != OEM_MANAGED_ALL) {
+ builder.append(", oemManaged=").append(mOemManaged);
+ }
return builder.toString();
}
@Override
public int hashCode() {
return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
- mDefaultNetwork, mSubType);
+ mDefaultNetwork, mSubType, mOemManaged);
}
@Override
@@ -338,7 +365,8 @@
&& mMetered == other.mMetered
&& mRoaming == other.mRoaming
&& mDefaultNetwork == other.mDefaultNetwork
- && mSubType == other.mSubType;
+ && mSubType == other.mSubType
+ && mOemManaged == other.mOemManaged;
}
return false;
}
@@ -384,6 +412,7 @@
if (!matchesMetered(ident)) return false;
if (!matchesRoaming(ident)) return false;
if (!matchesDefaultNetwork(ident)) return false;
+ if (!matchesOemNetwork(ident)) return false;
switch (mMatchRule) {
case MATCH_MOBILE:
@@ -425,6 +454,13 @@
|| (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
}
+ private boolean matchesOemNetwork(NetworkIdentity ident) {
+ return (mOemManaged == OEM_MANAGED_ALL)
+ || (mOemManaged == OEM_MANAGED_YES
+ && ident.mOemManaged != OEM_NONE)
+ || (mOemManaged == ident.mOemManaged);
+ }
+
private boolean matchesCollapsedRatType(NetworkIdentity ident) {
return mSubType == NETWORK_TYPE_ALL
|| getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java
new file mode 100644
index 0000000..6bbc6b1
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert IkeTrafficSelector to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeTrafficSelectorUtils {
+ private static final String START_PORT_KEY = "START_PORT_KEY";
+ private static final String END_PORT_KEY = "END_PORT_KEY";
+ private static final String START_ADDRESS_KEY = "START_ADDRESS_KEY";
+ private static final String END_ADDRESS_KEY = "END_ADDRESS_KEY";
+
+ /** Constructs an IkeTrafficSelector by deserializing a PersistableBundle. */
+ @NonNull
+ public static IkeTrafficSelector fromPersistableBundle(@NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ final int startPort = in.getInt(START_PORT_KEY);
+ final int endPort = in.getInt(END_PORT_KEY);
+
+ final String startingAddress = in.getString(START_ADDRESS_KEY);
+ final String endingAddress = in.getString(END_ADDRESS_KEY);
+ Objects.requireNonNull(startingAddress, "startAddress was null");
+ Objects.requireNonNull(startingAddress, "endAddress was null");
+
+ return new IkeTrafficSelector(
+ startPort,
+ endPort,
+ InetAddresses.parseNumericAddress(startingAddress),
+ InetAddresses.parseNumericAddress(endingAddress));
+ }
+
+ /** Serializes an IkeTrafficSelector to a PersistableBundle. */
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull IkeTrafficSelector ts) {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putInt(START_PORT_KEY, ts.startPort);
+ result.putInt(END_PORT_KEY, ts.endPort);
+ result.putString(START_ADDRESS_KEY, ts.startingAddress.getHostAddress());
+ result.putString(END_ADDRESS_KEY, ts.endingAddress.getHostAddress());
+
+ return result;
+ }
+}
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index c6efaac..2b6f336 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -47,6 +47,7 @@
POWER_COMPONENT_SYSTEM_SERVICES,
POWER_COMPONENT_SENSORS,
POWER_COMPONENT_GNSS,
+ POWER_COMPONENT_WIFI,
POWER_COMPONENT_WAKELOCK,
POWER_COMPONENT_SCREEN,
POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
@@ -66,6 +67,7 @@
public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
public static final int POWER_COMPONENT_SENSORS = 9;
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;
// Power that is re-attributed to other battery consumers. For example, for System Server
@@ -94,6 +96,7 @@
TIME_COMPONENT_MOBILE_RADIO,
TIME_COMPONENT_SENSORS,
TIME_COMPONENT_GNSS,
+ TIME_COMPONENT_WIFI,
TIME_COMPONENT_WAKELOCK,
TIME_COMPONENT_SCREEN,
})
@@ -112,6 +115,7 @@
public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
public static final int TIME_COMPONENT_SENSORS = 9;
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;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cf9b534..6901df7 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2179,12 +2179,6 @@
public abstract void finishIteratingHistoryLocked();
- public abstract boolean startIteratingOldHistoryLocked();
-
- public abstract boolean getNextOldHistoryLocked(HistoryItem out);
-
- public abstract void finishIteratingOldHistoryLocked();
-
/**
* Return the base time offset for the battery history.
*/
@@ -7061,24 +7055,6 @@
finishIteratingHistoryLocked();
}
}
-
- if (startIteratingOldHistoryLocked()) {
- try {
- final HistoryItem rec = new HistoryItem();
- pw.println("Old battery History:");
- HistoryPrinter hprinter = new HistoryPrinter();
- long baseTime = -1;
- while (getNextOldHistoryLocked(rec)) {
- if (baseTime < 0) {
- baseTime = rec.time;
- }
- hprinter.printNextItem(pw, rec, baseTime, false, (flags&DUMP_VERBOSE) != 0);
- }
- pw.println();
- } finally {
- finishIteratingOldHistoryLocked();
- }
- }
}
if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 35a5a7c..de7b885 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -20,6 +20,9 @@
import android.util.Range;
import android.util.SparseArray;
+import com.android.internal.os.BatteryStatsHistory;
+import com.android.internal.os.BatteryStatsHistoryIterator;
+
import java.util.ArrayList;
import java.util.List;
@@ -37,12 +40,16 @@
private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
+ private final Parcel mHistoryBuffer;
+ private final List<BatteryStats.HistoryTag> mHistoryTagPool;
private BatteryUsageStats(@NonNull Builder builder) {
mStatsStartRealtimeMs = builder.mStatsStartRealtimeMs;
mDischargePercentage = builder.mDischargePercentage;
mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
+ mHistoryBuffer = builder.mHistoryBuffer;
+ mHistoryTagPool = builder.mHistoryTagPool;
double totalPower = 0;
@@ -125,6 +132,19 @@
return mUserBatteryConsumers;
}
+ /**
+ * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
+ */
+ @NonNull
+ public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
+ if (mHistoryBuffer == null) {
+ throw new IllegalStateException(
+ "Battery history was not requested in the BatteryUsageStatsQuery");
+ }
+ return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer),
+ mHistoryTagPool);
+ }
+
@Override
public int describeContents() {
return 0;
@@ -142,6 +162,29 @@
source.readParcelableList(mSystemBatteryConsumers, getClass().getClassLoader());
mUserBatteryConsumers = new ArrayList<>();
source.readParcelableList(mUserBatteryConsumers, getClass().getClassLoader());
+ if (source.readBoolean()) {
+ mHistoryBuffer = Parcel.obtain();
+ mHistoryBuffer.setDataSize(0);
+ mHistoryBuffer.setDataPosition(0);
+
+ int historyBufferSize = source.readInt();
+ int curPos = source.dataPosition();
+ mHistoryBuffer.appendFrom(source, curPos, historyBufferSize);
+ source.setDataPosition(curPos + historyBufferSize);
+
+ int historyTagCount = source.readInt();
+ mHistoryTagPool = new ArrayList<>(historyTagCount);
+ for (int i = 0; i < historyTagCount; i++) {
+ BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag();
+ tag.string = source.readString();
+ tag.uid = source.readInt();
+ tag.poolIdx = source.readInt();
+ mHistoryTagPool.add(tag);
+ }
+ } else {
+ mHistoryBuffer = null;
+ mHistoryTagPool = null;
+ }
}
@Override
@@ -154,6 +197,23 @@
dest.writeParcelableList(mUidBatteryConsumers, flags);
dest.writeParcelableList(mSystemBatteryConsumers, flags);
dest.writeParcelableList(mUserBatteryConsumers, flags);
+ if (mHistoryBuffer != null) {
+ dest.writeBoolean(true);
+
+ final int historyBufferSize = mHistoryBuffer.dataSize();
+ dest.writeInt(historyBufferSize);
+ dest.appendFrom(mHistoryBuffer, 0, historyBufferSize);
+
+ dest.writeInt(mHistoryTagPool.size());
+ for (int i = mHistoryTagPool.size() - 1; i >= 0; i--) {
+ final BatteryStats.HistoryTag tag = mHistoryTagPool.get(i);
+ dest.writeString(tag.string);
+ dest.writeInt(tag.uid);
+ dest.writeInt(tag.poolIdx);
+ }
+ } else {
+ dest.writeBoolean(false);
+ }
}
@NonNull
@@ -183,6 +243,8 @@
new SparseArray<>();
private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
new SparseArray<>();
+ private Parcel mHistoryBuffer;
+ private List<BatteryStats.HistoryTag> mHistoryTagPool;
public Builder(int customPowerComponentCount, int customTimeComponentCount) {
mCustomPowerComponentCount = customPowerComponentCount;
@@ -227,6 +289,17 @@
}
/**
+ * Sets the parceled recent history.
+ */
+ @NonNull
+ public Builder setBatteryHistory(Parcel historyBuffer,
+ List<BatteryStats.HistoryTag> historyTagPool) {
+ mHistoryBuffer = historyBuffer;
+ mHistoryTagPool = historyTagPool;
+ return this;
+ }
+
+ /**
* Creates or returns a exiting UidBatteryConsumer, which represents battery attribution
* data for an individual UID.
*/
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 17cb735..9518bf1 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -40,6 +40,7 @@
*/
@IntDef(flag = true, prefix = { "FLAG_BATTERY_USAGE_STATS_" }, value = {
FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL,
+ FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface BatteryUsageStatsFlags {}
@@ -53,6 +54,12 @@
*/
public static final int FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL = 1;
+ /**
+ * Indicates that battery history should be included in the BatteryUsageStats.
+ * @hide
+ */
+ public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 2;
+
private final int mFlags;
@NonNull
private final int[] mUserIds;
@@ -146,10 +153,10 @@
}
/**
- * Sets flags to modify the behavior of {@link BatteryStatsManager#getBatteryUsageStats}.
+ * Requests that battery history be included in the BatteryUsageStats.
*/
- public Builder setFlags(@BatteryUsageStatsFlags int flags) {
- mFlags = flags;
+ public Builder includeBatteryHistory() {
+ mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY;
return this;
}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index a435ac1..73bb8d5 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -68,8 +68,11 @@
/**
* An interface describing the callback for bugreport progress and status.
*
- * <p>In general, callers can expect to receive {@link #onProgress} calls as the bugreport
- * progresses, followed by a terminal call to either {@link #onFinished} or {@link #onError}.
+ * <p>Callers will receive {@link #onProgress} calls as the bugreport progresses, followed by a
+ * terminal call to either {@link #onFinished} or {@link #onError}.
+ *
+ * <p>If an issue is encountered while starting the bugreport asynchronously, callers will
+ * receive an {@link #onError} call without any {@link #onProgress} callbacks.
*/
public abstract static class BugreportCallback {
/**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 7437e037..087568d 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -113,7 +113,7 @@
boolean hasBadge(int userId);
boolean isUserUnlocked(int userId);
boolean isUserRunning(int userId);
- boolean isUserForeground();
+ boolean isUserForeground(int userId);
boolean isUserNameSet(int userId);
boolean hasRestrictedProfiles();
boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userId, in IntentSender target, int flags);
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index e29d756..d8f6344 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -338,8 +338,7 @@
try {
time = mMgr.getGnssTimeMillis();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
- return 0;
+ throw e.rethrowFromSystemServer();
}
if (time == null) {
throw new DateTimeException("Gnss based time is not available.");
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index 1bdc82a..97e03e9 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -38,6 +38,23 @@
"include-filter": "com.android.server.pm.parsing.PackageInfoUserFieldsTest"
}
]
+ },
+ {
+ "file_patterns": ["BatteryStats.java"],
+ "name": "FrameworksCoreTests",
+ "options": [
+ { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+ { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+ ]
+ },
+ {
+ "file_patterns": ["BatteryStats.java"],
+ "name": "FrameworksServicesTests",
+ "options": [
+ { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+ { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+ { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+ ]
}
],
"postsubmit": [
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index bb40d90..dfa0c39 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -16,9 +16,13 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Contains power consumption data attributed to a specific UID.
*
@@ -26,9 +30,37 @@
*/
public final class UidBatteryConsumer extends BatteryConsumer implements Parcelable {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ STATE_FOREGROUND,
+ STATE_BACKGROUND
+ })
+ public @interface State {
+ }
+
+ /**
+ * The state of an application when it is either running a foreground (top) activity
+ * or a foreground service.
+ */
+ public static final int STATE_FOREGROUND = 0;
+
+ /**
+ * The state of an application when it is running in the background, including the following
+ * states:
+ *
+ * {@link android.app.ActivityManager#PROCESS_STATE_IMPORTANT_BACKGROUND},
+ * {@link android.app.ActivityManager#PROCESS_STATE_TRANSIENT_BACKGROUND},
+ * {@link android.app.ActivityManager#PROCESS_STATE_BACKUP},
+ * {@link android.app.ActivityManager#PROCESS_STATE_SERVICE},
+ * {@link android.app.ActivityManager#PROCESS_STATE_RECEIVER}.
+ */
+ public static final int STATE_BACKGROUND = 1;
+
private final int mUid;
@Nullable
private final String mPackageWithHighestDrain;
+ private final long mTimeInForegroundMs;
+ private final long mTimeInBackgroundMs;
public int getUid() {
return mUid;
@@ -39,16 +71,33 @@
return mPackageWithHighestDrain;
}
+ /**
+ * Returns the amount of time in milliseconds this UID spent in the specified state.
+ */
+ public long getTimeInStateMs(@State int state) {
+ switch (state) {
+ case STATE_BACKGROUND:
+ return mTimeInBackgroundMs;
+ case STATE_FOREGROUND:
+ return mTimeInForegroundMs;
+ }
+ return 0;
+ }
+
private UidBatteryConsumer(@NonNull Builder builder) {
super(builder.mPowerComponentsBuilder.build());
mUid = builder.mUid;
mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
+ mTimeInForegroundMs = builder.mTimeInForegroundMs;
+ mTimeInBackgroundMs = builder.mTimeInBackgroundMs;
}
private UidBatteryConsumer(@NonNull Parcel source) {
super(new PowerComponents(source));
mUid = source.readInt();
mPackageWithHighestDrain = source.readString();
+ mTimeInForegroundMs = source.readLong();
+ mTimeInBackgroundMs = source.readLong();
}
/**
@@ -59,6 +108,8 @@
super.writeToParcel(dest, flags);
dest.writeInt(mUid);
dest.writeString(mPackageWithHighestDrain);
+ dest.writeLong(mTimeInForegroundMs);
+ dest.writeLong(mTimeInBackgroundMs);
}
@NonNull
@@ -84,6 +135,8 @@
private final BatteryStats.Uid mBatteryStatsUid;
private final int mUid;
private String mPackageWithHighestDrain;
+ public long mTimeInForegroundMs;
+ public long mTimeInBackgroundMs;
private boolean mExcludeFromBatteryUsageStats;
public Builder(int customPowerComponentCount, int customTimeComponentCount,
@@ -113,6 +166,25 @@
}
/**
+ * Sets the duration, in milliseconds, that this UID was active in a particular state,
+ * such as foreground or background.
+ */
+ @NonNull
+ public Builder setTimeInStateMs(@State int state, long timeInStateMs) {
+ switch (state) {
+ case STATE_FOREGROUND:
+ mTimeInForegroundMs = timeInStateMs;
+ break;
+ case STATE_BACKGROUND:
+ mTimeInBackgroundMs = timeInStateMs;
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported state: " + state);
+ }
+ return this;
+ }
+
+ /**
* Marks the UidBatteryConsumer for exclusion from the result set.
*/
public Builder excludeFromBatteryUsageStats() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 8bdfd3d..5069e031 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1688,6 +1688,7 @@
* @return Whether guest user is always ephemeral
* @hide
*/
+ @TestApi
public static boolean isGuestUserEphemeral() {
return Resources.getSystem()
.getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
@@ -1802,6 +1803,20 @@
}
/**
+ * @return the user type of the context user.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
+ @UserHandleAware
+ public @NonNull String getUserType() {
+ UserInfo userInfo = getUserInfo(mUserId);
+ return userInfo == null ? "" : userInfo.userType;
+ }
+
+ /**
* Returns the user name of the context user. This call is only available to applications on
* the system image; it requires the {@code android.permission.MANAGE_USERS} or {@code
* android.permission.GET_ACCOUNTS_PRIVILEGED} permissions.
@@ -1809,7 +1824,8 @@
* @return the user name
*/
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
- android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}, conditional = true)
+ android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED,
+ android.Manifest.permission.CREATE_USERS}, conditional = true)
@UserHandleAware
public @NonNull String getUserName() {
if (UserHandle.myUserId() == mUserId) {
@@ -2300,13 +2316,14 @@
}
/**
- * Checks if the calling user is running on foreground.
+ * Checks if the context user is running in the foreground.
*
- * @return whether the calling user is running on foreground.
+ * @return whether the context user is running in the foreground.
*/
+ @UserHandleAware
public boolean isUserForeground() {
try {
- return mService.isUserForeground();
+ return mService.isUserForeground(mUserId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -2792,6 +2809,7 @@
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
+ @TestApi
public @Nullable UserInfo createUser(@Nullable String name, @NonNull String userType,
@UserInfoFlag int flags) {
try {
@@ -2828,6 +2846,7 @@
* @throws UserOperationException if the user could not be created.
* @hide
*/
+ @TestApi
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
public @NonNull UserInfo preCreateUser(@NonNull String userType)
@@ -2976,10 +2995,11 @@
*
* @hide
*/
+ @TestApi
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createProfileForUser(String name, @NonNull String userType,
- @UserInfoFlag int flags, @UserIdInt int userId, String[] disallowedPackages) {
+ public @Nullable UserInfo createProfileForUser(@Nullable String name, @NonNull String userType,
+ @UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages) {
try {
return mService.createProfileForUserWithThrow(name, userType, flags, userId,
disallowedPackages);
@@ -3022,9 +3042,10 @@
*
* @hide
*/
+ @TestApi
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createRestrictedProfile(String name) {
+ public @Nullable UserInfo createRestrictedProfile(@Nullable String name) {
try {
UserHandle parentUserHandle = Process.myUserHandle();
UserInfo user = mService.createRestrictedProfileWithThrow(name,
@@ -3248,10 +3269,11 @@
/**
* Return the number of users currently created on the device.
- * <p>This API is not for use by third-party apps. It requires the {@code MANAGE_USERS}
- * permission.</p>
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
public int getUserCount() {
List<UserInfo> users = getUsers();
return users != null ? users.size() : 1;
@@ -3274,7 +3296,10 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
public List<UserInfo> getUsers() {
return getUsers(/*excludePartial= */ true, /* excludeDying= */ false,
/* excludePreCreated= */ true);
@@ -3292,7 +3317,10 @@
* @return the list of users that were created.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
public @NonNull List<UserInfo> getAliveUsers() {
return getUsers(/*excludePartial= */ true, /* excludeDying= */ true,
/* excludePreCreated= */ true);
@@ -3306,7 +3334,10 @@
*/
@Deprecated
@UnsupportedAppUsage
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
return getUsers(/*excludePartial= */ true, excludeDying,
/* excludePreCreated= */ true);
@@ -3317,8 +3348,12 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
- public List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying,
+ @TestApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
+ public @NonNull List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying,
boolean excludePreCreated) {
try {
return mService.getUsers(excludePartial, excludeDying, excludePreCreated);
@@ -3335,7 +3370,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
public @NonNull List<UserHandle> getUserHandles(boolean excludeDying) {
List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying,
/* excludePreCreated= */ true);
@@ -3354,7 +3392,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.CREATE_USERS
+ })
public long[] getSerialNumbersOfUsers(boolean excludeDying) {
List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying,
/* excludePreCreated= */ true);
@@ -3678,7 +3719,10 @@
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS
+ })
public UserInfo getProfileParent(@UserIdInt int userId) {
try {
return mService.getProfileParent(userId);
@@ -3697,7 +3741,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS
+ })
public @Nullable UserHandle getProfileParent(@NonNull UserHandle user) {
UserInfo info = getProfileParent(user.getIdentifier());
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 06203ff..9ffc5aa0 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -426,7 +426,7 @@
// avoid writing a partial response to the zygote.
for (String arg : args) {
// Making two indexOf calls here is faster than running a manually fused loop due
- // to the fact that indexOf is a optimized intrinsic.
+ // to the fact that indexOf is an optimized intrinsic.
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("Embedded newlines not allowed");
} else if (arg.indexOf('\r') >= 0) {
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 4669b20..0041699 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -196,4 +196,6 @@
void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
void fixupAppDir(in String path) = 89;
void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
-}
+ void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91;
+ void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92;
+ }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 3a5426c..7c8874c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -2699,6 +2699,80 @@
}
}
+ /**
+ * Reason to provide if app IO is blocked/resumed because of transcoding
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 0;
+
+ /**
+ * Constants for use with
+ * {@link #notifyAppIoBlocked} and {@link notifyAppIoResumed}, to specify the reason an app's
+ * IO is blocked/resumed.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "APP_IO_BLOCKED_REASON_" }, value = {
+ APP_IO_BLOCKED_REASON_TRANSCODING
+ })
+ public @interface AppIoBlockedReason {}
+
+ /**
+ * Notify the system that an app with {@code uid} and {@code tid} is blocked on an IO request on
+ * {@code volumeUuid} for {@code reason}.
+ *
+ * This blocked state can be used to modify the ANR behavior for the app while it's blocked.
+ * For example during transcoding.
+ *
+ * This can only be called by the {@link ExternalStorageService} holding the
+ * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
+ *
+ * @param volumeUuid the UUID of the storage volume that the app IO is blocked on
+ * @param uid the UID of the app blocked on IO
+ * @param tid the tid of the app blocked on IO
+ * @param reason the reason the app is blocked on IO
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void notifyAppIoBlocked(@NonNull String volumeUuid, int uid, int tid,
+ @AppIoBlockedReason int reason) {
+ try {
+ mStorageManager.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notify the system that an app with {@code uid} and {@code tid} has resmued a previously
+ * blocked IO request on {@code volumeUuid} for {@code reason}.
+ *
+ * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
+ *
+ * This can only be called by the {@link ExternalStorageService} holding the
+ * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
+ *
+ * @param volumeUuid the UUID of the storage volume that the app IO is resumed on
+ * @param uid the UID of the app resuming IO
+ * @param tid the tid of the app resuming IO
+ * @param reason the reason the app is resuming IO
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void notifyAppIoResumed(@NonNull String volumeUuid, int uid, int tid,
+ @AppIoBlockedReason int reason) {
+ try {
+ mStorageManager.notifyAppIoResumed(volumeUuid, uid, tid, reason);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private final Object mFuseAppLoopLock = new Object();
@GuardedBy("mFuseAppLoopLock")
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index ff01011..bae36b29 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -485,10 +485,6 @@
* One for cases where the installer of the package allowlists a permission. This list
* corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be
* accessed by pre-installed holders of a dedicated permission or the installer on record.
- * <li>
- * One for cases where the system exempts the permission when granting a role. This list
- * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be
- * accessed by pre-installed holders of a dedicated permission.
* </ol>
*
* @param packageName the app for which to get allowlisted permissions
@@ -502,7 +498,6 @@
* @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM
* @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE
* @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER
- * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @hide Pending API
*/
@@ -549,10 +544,6 @@
* One for cases where the installer of the package allowlists a permission. This list
* corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be
* accessed by pre-installed holders of a dedicated permission or the installer on record.
- * <li>
- * One for cases where the system exempts the permission when granting a role. This list
- * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be
- * accessed by pre-installed holders of a dedicated permission.
* </ol>
* <p>
* You need to specify the allowlists for which to set the allowlisted permissions which will
@@ -570,7 +561,6 @@
* @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM
* @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE
* @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER
- * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @hide Pending API
*/
@@ -613,10 +603,6 @@
* One for cases where the installer of the package allowlists a permission. This list
* corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be
* accessed by pre-installed holders of a dedicated permission or the installer on record.
- * <li>
- * One for cases where the system exempts the permission when granting a role. This list
- * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be
- * accessed by pre-installed holders of a dedicated permission.
* </ol>
* <p>
* You need to specify the allowlists for which to set the allowlisted permissions which will
@@ -634,7 +620,6 @@
* @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM
* @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE
* @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER
- * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE
*
* @hide Pending API
*/
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 0e35ef9..4c9e77c 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -57,6 +57,8 @@
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
+import com.android.internal.R;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -186,6 +188,15 @@
== PackageManager.PERMISSION_GRANTED;
}
+ private boolean isSpeechRecognizerUsage(String op, String packageName) {
+ if (!OPSTR_RECORD_AUDIO.equals(op)) {
+ return false;
+ }
+
+ return packageName.equals(
+ mContext.getString(R.string.config_systemSpeechRecognizer));
+ }
+
/**
* @see PermissionManager.getIndicatorAppOpUsageData
*/
@@ -317,7 +328,8 @@
if (packageName.equals(SYSTEM_PKG)
|| (!isUserSensitive(packageName, user, op)
&& !isLocationProvider(packageName, user)
- && !isAppPredictor(packageName, user))) {
+ && !isAppPredictor(packageName, user))
+ && !isSpeechRecognizerUsage(op, packageName)) {
continue;
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 4354920..6e89faf 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -157,6 +157,14 @@
public static final String NAMESPACE_BLUETOOTH = "bluetooth";
/**
+ * Namespace for features relating to clipboard.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_CLIPBOARD = "clipboard";
+
+ /**
* Namespace for all networking connectivity related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 09d0af1..85cef84 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10512,18 +10512,6 @@
"force_desktop_mode_on_external_displays";
/**
- * Whether to allow non-resizable apps to be freeform.
- *
- * TODO(b/176061101) remove after update all usages
- * @deprecated use {@link #DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}
- * @hide
- */
- @Deprecated
- @Readable
- public static final String DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM =
- "enable_sizecompat_freeform";
-
- /**
* Whether to allow non-resizable apps to be shown in multi-window. The app will be
* letterboxed if the request orientation is not met, and will be shown in size-compat
* mode if the container size has changed.
@@ -16576,30 +16564,6 @@
/**
* Performs a strict and comprehensive check of whether a calling package is allowed to
- * change the state of network, as the condition differs for pre-M, M+, and
- * privileged/preinstalled apps. The caller is expected to have either the
- * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
- * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
- * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
- * permission and cannot be revoked. See http://b/23597341
- *
- * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
- * of this app will be updated to the current time.
- * @hide
- */
- public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid,
- String callingPackage, String callingAttributionTag, boolean throwException) {
- if (context.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
- callingPackage, callingAttributionTag, throwException,
- AppOpsManager.OP_WRITE_SETTINGS, PM_CHANGE_NETWORK_STATE, true);
- }
-
- /**
- * Performs a strict and comprehensive check of whether a calling package is allowed to
* draw on top of other apps, as the conditions differs for pre-M, M+, and
* privileged/preinstalled apps. If the provided uid does not match the callingPackage,
* a negative result will be returned.
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index d859b1c..6788353 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -27,8 +27,11 @@
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.security.KeyStore;
-import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.KeyStore2;
import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore2.AndroidKeyStoreProvider;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
import com.android.internal.widget.ILockSettings;
@@ -709,10 +712,34 @@
*/
@NonNull Key getKeyFromGrant(@NonNull String grantAlias)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
- mKeyStore,
- grantAlias,
- KeyStore.UID_SELF);
+ if (grantAlias.startsWith(APPLICATION_KEY_GRANT_PREFIX)) {
+ return AndroidKeyStoreProvider
+ .loadAndroidKeyStoreSecretKeyFromKeystore(
+ KeyStore2.getInstance(),
+ getGrantDescriptor(grantAlias));
+ }
+ // TODO(b/171305545): remove KeyStore1 logic.
+ return android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
+ mKeyStore,
+ grantAlias,
+ KeyStore.UID_SELF);
+
+ }
+
+ private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:";
+
+ private static @Nullable KeyDescriptor getGrantDescriptor(String grantAlias) {
+ KeyDescriptor result = new KeyDescriptor();
+ result.domain = Domain.GRANT;
+ result.blob = null;
+ result.alias = null;
+ try {
+ result.nspace = Long.parseUnsignedLong(
+ grantAlias.substring(APPLICATION_KEY_GRANT_PREFIX.length()), 16);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ return result;
}
/**
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 73e66d0..7aa5bbc9 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -85,6 +85,10 @@
* android:name="android.service.notification.default_filter_types"
* android:value="1,2">
* </meta-data>
+ * <meta-data
+ * android:name="android.service.notification.disabled_filter_types"
+ * android:value="2">
+ * </meta-data>
* </service></pre>
*
* <p>The service should wait for the {@link #onListenerConnected()} event
@@ -123,6 +127,19 @@
= "android.service.notification.default_filter_types";
/**
+ * The name of the {@code meta-data} tag containing a comma separated list of default
+ * integer notification types that this listener never wants to receive. See
+ * {@link #FLAG_FILTER_TYPE_ONGOING},
+ * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING),
+ * and {@link #FLAG_FILTER_TYPE_SILENT}.
+ * <p>Types provided in this list will appear as 'off' and 'disabled' in the user interface,
+ * so users don't enable a type that the listener will never bridge to their paired devices.</p>
+ *
+ */
+ public static final String META_DATA_DISABLED_FILTER_TYPES
+ = "android.service.notification.disabled_filter_types";
+
+ /**
* {@link #getCurrentInterruptionFilter() Interruption filter} constant -
* Normal interruption filter.
*/
diff --git a/core/java/android/service/storage/ExternalStorageService.java b/core/java/android/service/storage/ExternalStorageService.java
index 87add57..1e07a87 100644
--- a/core/java/android/service/storage/ExternalStorageService.java
+++ b/core/java/android/service/storage/ExternalStorageService.java
@@ -102,14 +102,6 @@
*/
public static final String EXTRA_PACKAGE_NAME = "android.service.storage.extra.package_name";
- /**
- * {@link Bundle} key for a {@link Long} value.
- *
- * {@hide}
- */
- public static final String EXTRA_ANR_TIMEOUT_MS =
- "android.service.storage.extra.anr_timeout_ms";
-
/** @hide */
@IntDef(flag = true, prefix = {"FLAG_SESSION_"},
value = {FLAG_SESSION_TYPE_FUSE, FLAG_SESSION_ATTRIBUTE_INDEXABLE})
@@ -178,12 +170,12 @@
}
/**
- * Called when {@code packageName} is about to ANR
+ * Called when {@code packageName} is about to ANR. The {@link ExternalStorageService} can
+ * show a progress dialog for the {@code reason}.
*
- * @return ANR dialog delay in milliseconds
*/
- public long onGetAnrDelayMillis(@NonNull String packageName, int uid) {
- throw new UnsupportedOperationException("onGetAnrDelayMillis not implemented");
+ public void onAnrDelayStarted(@NonNull String packageName, int uid, int tid, int reason) {
+ throw new UnsupportedOperationException("onAnrDelayStarted not implemented");
}
@Override
@@ -247,14 +239,14 @@
}
@Override
- public void getAnrDelayMillis(String packageName, int uid, RemoteCallback callback)
- throws RemoteException {
+ public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason,
+ RemoteCallback callback) throws RemoteException {
mHandler.post(() -> {
try {
- long timeoutMs = onGetAnrDelayMillis(packageName, uid);
- sendTimeoutResult(packageName, timeoutMs, null /* throwable */, callback);
+ onAnrDelayStarted(packageName, uid, tid, reason);
+ sendResult(packageName, null /* throwable */, callback);
} catch (Throwable t) {
- sendTimeoutResult(packageName, 0 /* timeoutMs */, t, callback);
+ sendResult(packageName, t, callback);
}
});
}
@@ -267,16 +259,5 @@
}
callback.sendResult(bundle);
}
-
- private void sendTimeoutResult(String packageName, long timeoutMs, Throwable throwable,
- RemoteCallback callback) {
- Bundle bundle = new Bundle();
- bundle.putString(EXTRA_PACKAGE_NAME, packageName);
- bundle.putLong(EXTRA_ANR_TIMEOUT_MS, timeoutMs);
- if (throwable != null) {
- bundle.putParcelable(EXTRA_ERROR, new ParcelableException(throwable));
- }
- callback.sendResult(bundle);
- }
}
}
diff --git a/core/java/android/service/storage/IExternalStorageService.aidl b/core/java/android/service/storage/IExternalStorageService.aidl
index 2e0bd86..ba98efa 100644
--- a/core/java/android/service/storage/IExternalStorageService.aidl
+++ b/core/java/android/service/storage/IExternalStorageService.aidl
@@ -32,5 +32,6 @@
in RemoteCallback callback);
void freeCache(@utf8InCpp String sessionId, in String volumeUuid, long bytes,
in RemoteCallback callback);
- void getAnrDelayMillis(String packageName, int uid, in RemoteCallback callback);
+ void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason,
+ in RemoteCallback callback);
}
\ No newline at end of file
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 3c35d2c..7f1c5ff 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -19,15 +19,18 @@
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.CallSuper;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
+import android.media.AudioFormat;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
@@ -57,14 +60,21 @@
private final IHotwordDetectionService mInterface = new IHotwordDetectionService.Stub() {
@Override
- public void detectFromDspSource(int sessionId, IDspHotwordDetectionCallback callback)
+ public void detectFromDspSource(
+ ParcelFileDescriptor audioStream,
+ AudioFormat audioFormat,
+ long timeoutMillis,
+ IDspHotwordDetectionCallback callback)
throws RemoteException {
if (DBG) {
Log.d(TAG, "#detectFromDspSource");
}
mHandler.sendMessage(obtainMessage(HotwordDetectionService::onDetectFromDspSource,
HotwordDetectionService.this,
- sessionId, new DspHotwordDetectionCallback(callback)));
+ audioStream,
+ audioFormat,
+ timeoutMillis,
+ new DspHotwordDetectionCallback(callback)));
}
};
@@ -89,15 +99,24 @@
/**
* Detect the audio data generated from Dsp.
*
- * @param sessionId The session to use when attempting to capture more audio from the DSP
- * hardware.
+ * <p>Note: the clients are supposed to call {@code close} on the input stream when they are
+ * done with the operation in order to free up resources.
+ *
+ * @param audioStream Stream containing audio bytes returned from DSP
+ * @param audioFormat Format of the supplied audio
+ * @param timeoutMillis Timeout in milliseconds for the operation to invoke the callback. If
+ * the application fails to abide by the timeout, system will close the
+ * microphone and cancel the operation.
* @param callback Use {@link HotwordDetectionService#DspHotwordDetectionCallback} to return
* the detected result.
*
* @hide
*/
@SystemApi
- public void onDetectFromDspSource(int sessionId,
+ public void onDetectFromDspSource(
+ @NonNull ParcelFileDescriptor audioStream,
+ @NonNull AudioFormat audioFormat,
+ @DurationMillisLong long timeoutMillis,
@NonNull DspHotwordDetectionCallback callback) {
}
diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl
index 990ad45..cbe76e4 100644
--- a/core/java/android/service/voice/IHotwordDetectionService.aidl
+++ b/core/java/android/service/voice/IHotwordDetectionService.aidl
@@ -16,6 +16,8 @@
package android.service.voice;
+import android.media.AudioFormat;
+import android.os.ParcelFileDescriptor;
import android.service.voice.IDspHotwordDetectionCallback;
/**
@@ -24,5 +26,9 @@
* @hide
*/
oneway interface IHotwordDetectionService {
- void detectFromDspSource(int sessionId, in IDspHotwordDetectionCallback callback);
+ void detectFromDspSource(
+ in ParcelFileDescriptor audioStream,
+ in AudioFormat audioFormat,
+ long timeoutMillis,
+ in IDspHotwordDetectionCallback callback);
}
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index aef185c..33b7c75 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -18,6 +18,7 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -101,7 +102,7 @@
*
* If there is no update, this return 0.
*/
- public long getLastModifiedTimeMillis() {
+ public @CurrentTimeMillisLong long getLastModifiedTimeMillis() {
return mLastModifiedTimeMillis;
}
diff --git a/core/java/android/util/MergedConfiguration.java b/core/java/android/util/MergedConfiguration.java
index 3ac44aa..4328e08 100644
--- a/core/java/android/util/MergedConfiguration.java
+++ b/core/java/android/util/MergedConfiguration.java
@@ -33,9 +33,9 @@
*/
public class MergedConfiguration implements Parcelable {
- private Configuration mGlobalConfig = new Configuration();
- private Configuration mOverrideConfig = new Configuration();
- private Configuration mMergedConfig = new Configuration();
+ private final Configuration mGlobalConfig = new Configuration();
+ private final Configuration mOverrideConfig = new Configuration();
+ private final Configuration mMergedConfig = new Configuration();
public MergedConfiguration() {
}
@@ -59,15 +59,15 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mGlobalConfig, flags);
- dest.writeParcelable(mOverrideConfig, flags);
- dest.writeParcelable(mMergedConfig, flags);
+ mGlobalConfig.writeToParcel(dest, flags);
+ mOverrideConfig.writeToParcel(dest, flags);
+ mMergedConfig.writeToParcel(dest, flags);
}
public void readFromParcel(Parcel source) {
- mGlobalConfig = source.readParcelable(Configuration.class.getClassLoader());
- mOverrideConfig = source.readParcelable(Configuration.class.getClassLoader());
- mMergedConfig = source.readParcelable(Configuration.class.getClassLoader());
+ mGlobalConfig.readFromParcel(source);
+ mOverrideConfig.readFromParcel(source);
+ mMergedConfig.readFromParcel(source);
}
@Override
diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java
new file mode 100644
index 0000000..5a1b850
--- /dev/null
+++ b/core/java/android/view/CrossWindowBlurListeners.java
@@ -0,0 +1,137 @@
+/**
+ * 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.view;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.function.Consumer;
+
+/**
+ * Class that holds all registered {@link CrossWindowBlurEnabledListener}s. It listens
+ * for updates from the WindowManagerService and updates all registered listeners.
+ * @hide
+ */
+public final class CrossWindowBlurListeners {
+ private static final String TAG = "CrossWindowBlurListeners";
+
+ // property for background blur support in surface flinger
+ private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur";
+ public static final boolean CROSS_WINDOW_BLUR_SUPPORTED =
+ SystemProperties.get(BLUR_PROPERTY, "default").equals("1");
+
+ private static volatile CrossWindowBlurListeners sInstance;
+ private static final Object sLock = new Object();
+
+ private final BlurEnabledListenerInternal mListenerInternal = new BlurEnabledListenerInternal();
+ private final ArraySet<Consumer<Boolean>> mListeners = new ArraySet();
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+ private boolean mInternalListenerAttached = false;
+ private boolean mCrossWindowBlurEnabled;
+
+ private CrossWindowBlurListeners() {}
+
+ /**
+ * Returns a CrossWindowBlurListeners instance
+ */
+ public static CrossWindowBlurListeners getInstance() {
+ CrossWindowBlurListeners instance = sInstance;
+ if (instance == null) {
+
+ synchronized (sLock) {
+ instance = sInstance;
+ if (instance == null) {
+ instance = new CrossWindowBlurListeners();
+ sInstance = instance;
+ }
+ }
+ }
+ return instance;
+ }
+
+ boolean isCrossWindowBlurEnabled() {
+ synchronized (sLock) {
+ attachInternalListenerIfNeededLocked();
+ return mCrossWindowBlurEnabled;
+ }
+ }
+
+ void addListener(Consumer<Boolean> listener) {
+ if (listener == null) return;
+
+ synchronized (sLock) {
+ attachInternalListenerIfNeededLocked();
+
+ mListeners.add(listener);
+ notifyListenerOnMain(listener, mCrossWindowBlurEnabled);
+ }
+ }
+
+
+ void removeListener(Consumer<Boolean> listener) {
+ if (listener == null) return;
+
+ synchronized (sLock) {
+ mListeners.remove(listener);
+
+ if (mInternalListenerAttached && mListeners.size() == 0) {
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .unregisterCrossWindowBlurEnabledListener(mListenerInternal);
+ mInternalListenerAttached = false;
+ } catch (RemoteException e) {
+ Log.d(TAG, "Could not unregister ICrossWindowBlurEnabledListener");
+ }
+ }
+ }
+ }
+
+ private void attachInternalListenerIfNeededLocked() {
+ if (!mInternalListenerAttached) {
+ try {
+ mCrossWindowBlurEnabled = WindowManagerGlobal.getWindowManagerService()
+ .registerCrossWindowBlurEnabledListener(mListenerInternal);
+ mInternalListenerAttached = true;
+ } catch (RemoteException e) {
+ Log.d(TAG, "Could not register ICrossWindowBlurEnabledListener");
+ }
+ }
+ }
+
+ private void notifyListenerOnMain(Consumer<Boolean> listener, boolean enabled) {
+ mMainHandler.post(() -> {
+ listener.accept(enabled);
+ });
+ }
+
+ private final class BlurEnabledListenerInternal extends ICrossWindowBlurEnabledListener.Stub {
+ @Override
+ public void onCrossWindowBlurEnabledChanged(boolean enabled) {
+ synchronized (sLock) {
+ mCrossWindowBlurEnabled = enabled;
+
+ for (int i = 0; i < mListeners.size(); i++) {
+ notifyListenerOnMain(mListeners.valueAt(i), enabled);
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 0ba1dfe..8117c96 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -34,6 +34,7 @@
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Build;
@@ -1181,6 +1182,18 @@
}
/**
+ * Returns the product-specific information about the display or the directly connected
+ * device on the display chain.
+ * For example, if the display is transitively connected, this field may contain product
+ * information about the intermediate device.
+ * Returns {@code null} if product information is not available.
+ */
+ @Nullable
+ public DeviceProductInfo getDeviceProductInfo() {
+ return mDisplayInfo.deviceProductInfo;
+ }
+
+ /**
* Gets display metrics that describe the size and density of this display.
* The size returned by this method does not necessarily represent the
* actual raw size (native resolution) of the display.
diff --git a/core/java/android/view/ICrossWindowBlurEnabledListener.aidl b/core/java/android/view/ICrossWindowBlurEnabledListener.aidl
new file mode 100644
index 0000000..69286e2
--- /dev/null
+++ b/core/java/android/view/ICrossWindowBlurEnabledListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Listener to be invoked when cross-window blur is enabled or disabled.
+ * {@hide}
+ */
+oneway interface ICrossWindowBlurEnabledListener {
+ /**
+ * Method that will be invoked when cross-window blur is enabled or disabled.
+ * @param enabled True if cross-window blur is enabled.
+ */
+ void onCrossWindowBlurEnabledChanged(boolean enabled);
+}
diff --git a/core/java/android/view/IScrollCaptureCallbacks.aidl b/core/java/android/view/IScrollCaptureCallbacks.aidl
index d97e3c6..26eaac0 100644
--- a/core/java/android/view/IScrollCaptureCallbacks.aidl
+++ b/core/java/android/view/IScrollCaptureCallbacks.aidl
@@ -16,12 +16,10 @@
package android.view;
-import android.graphics.Point;
import android.graphics.Rect;
+import android.view.ScrollCaptureResponse;
import android.view.Surface;
-import android.view.IScrollCaptureConnection;
-
/**
* Asynchronous callback channel for responses to scroll capture requests.
*
@@ -29,34 +27,30 @@
*/
interface IScrollCaptureCallbacks {
/**
- * Scroll capture is available, and a connection has been provided.
+ * Provides the result of WindowManagerService#requestScrollCapture
*
- * @param connection a connection to a window process and scrollable content
- * @param scrollAreaInWindow the location of scrolling in global (window) coordinate space
+ * @param response the response which describes the result
*/
- oneway void onConnected(in IScrollCaptureConnection connection, in Rect scrollBounds,
- in Point positionInWindow);
+ oneway void onScrollCaptureResponse(in ScrollCaptureResponse response);
/**
- * The window does not support scroll capture.
- */
- oneway void onUnavailable();
-
- /**
- * Called when the remote end has confirmed the request and is ready to begin providing image
- * requests.
+ * Called in reply to IScrollCaptureConnection#startCapture, when the remote end has confirmed
+ * the request and is ready to begin capturing images.
*/
oneway void onCaptureStarted();
/**
- * Received a response from a capture request.
+ * Received a response from a capture request. The provided rectangle indicates the portion
+ * of the requested rectangle which was captured. An empty rectangle indicates that the request
+ * could not be satisfied (most commonly due to the available scrolling range).
+ *
+ * @param flags flags describing additional status of the result
+ * @param capturedArea the actual area of the image captured
*/
- oneway void onCaptureBufferSent(long frameNumber, in Rect capturedArea);
+ oneway void onImageRequestCompleted(int flags, in Rect capturedArea);
/**
- * Signals that the capture session has completed and the target window may be returned to
- * normal interactive use. This may be due to normal shutdown, or after a timeout or other
- * unrecoverable state change such as activity lifecycle, window visibility or focus.
+ * Signals that the capture session has completed and the target window is ready for normal use.
*/
- oneway void onConnectionClosed();
+ oneway void onCaptureEnded();
}
diff --git a/core/java/android/view/IScrollCaptureConnection.aidl b/core/java/android/view/IScrollCaptureConnection.aidl
index 63a4f48..c55e888 100644
--- a/core/java/android/view/IScrollCaptureConnection.aidl
+++ b/core/java/android/view/IScrollCaptureConnection.aidl
@@ -17,33 +17,45 @@
package android.view;
import android.graphics.Rect;
+import android.os.ICancellationSignal;
import android.view.Surface;
/**
- * Interface implemented by a client of the Scroll Capture framework to receive requests
- * to start, capture images and end the session.
+ * A remote connection to a scroll capture target.
*
* {@hide}
*/
interface IScrollCaptureConnection {
/**
- * Informs the client that it has been selected for scroll capture and should prepare to
- * to begin handling capture requests.
- */
- oneway void startCapture(in Surface surface);
-
- /**
- * Request the client capture an image within the provided rectangle.
+ * Informs the target that it has been selected for scroll capture.
*
- * @see android.view.ScrollCaptureCallback#onScrollCaptureRequest
+ * @param surface a return channel for image buffers
+ *
+ * @return a cancallation signal which is used cancel the request
*/
- oneway void requestImage(in Rect captureArea);
+ ICancellationSignal startCapture(in Surface surface);
/**
- * Inform the client that capture has ended. The client should shut down and release all
- * local resources in use and prepare for return to normal interactive usage.
+ * Request the target capture an image within the provided rectangle.
+ *
+ * @param surface a return channel for image buffers
+ * @param signal a cancallation signal which can interrupt the request
+ *
+ * @return a cancallation signal which is used cancel the request
*/
- oneway void endCapture();
+ ICancellationSignal requestImage(in Rect captureArea);
+
+ /**
+ * Inform the target that capture has ended.
+ *
+ * @return a cancallation signal which is used cancel the request
+ */
+ ICancellationSignal endCapture();
+
+ /**
+ * Closes the connection.
+ */
+ oneway void close();
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index afdf798..5477800 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,6 +35,7 @@
import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.ICrossWindowBlurEnabledListener;
import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
@@ -730,7 +731,7 @@
void showGlobalActions();
/**
- * Sets layer tracing flags for SurfaceFlingerTrace.
+ * Sets layer tracing flags for SurfaceFlingerTrace.
*
* @param flags see definition in SurfaceTracing.cpp
*/
@@ -799,4 +800,20 @@
* @param clientToken the window context's token
*/
void unregisterWindowContextListener(IBinder clientToken);
+
+ /**
+ * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled.
+ *
+ * @param listener the listener to be registered
+ * @return true if cross-window blur is currently enabled; false otherwise
+ */
+ boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
+
+ /**
+ * Unregisters a listener which was registered with
+ * {@link #registerCrossWindowBlurEnabledListener()}.
+ *
+ * @param listener the listener to be unregistered
+ */
+ void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 5f2bccc..e6cf683 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -261,11 +261,7 @@
public InsetsSource(Parcel in) {
mType = in.readInt();
- if (in.readInt() != 0) {
- mFrame = Rect.CREATOR.createFromParcel(in);
- } else {
- mFrame = null;
- }
+ mFrame = Rect.CREATOR.createFromParcel(in);
if (in.readInt() != 0) {
mVisibleFrame = Rect.CREATOR.createFromParcel(in);
} else {
@@ -282,12 +278,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
- if (mFrame != null) {
- dest.writeInt(1);
- mFrame.writeToParcel(dest, 0);
- } else {
- dest.writeInt(0);
- }
+ mFrame.writeToParcel(dest, 0);
if (mVisibleFrame != null) {
dest.writeInt(1);
mVisibleFrame.writeToParcel(dest, 0);
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index c717c2a..1d4b411 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -77,8 +77,8 @@
public InsetsSourceControl(Parcel in) {
mType = in.readInt();
- mLeash = in.readParcelable(null /* loader */);
- mSurfacePosition = in.readParcelable(null /* loader */);
+ mLeash = in.readTypedObject(SurfaceControl.CREATOR);
+ mSurfacePosition = in.readTypedObject(Point.CREATOR);
mSkipAnimationOnce = in.readBoolean();
}
@@ -119,8 +119,8 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
- dest.writeParcelable(mLeash, 0 /* flags*/);
- dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
+ dest.writeTypedObject(mLeash, 0 /* parcelableFlags */);
+ dest.writeTypedObject(mSurfacePosition, 0 /* parcelableFlags */);
dest.writeBoolean(mSkipAnimationOnce);
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 21dd1fb..fce1952 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -156,7 +156,7 @@
static final int ISIDE_FLOATING = 4;
static final int ISIDE_UNKNOWN = 5;
- private InsetsSource[] mSources = new InsetsSource[SIZE];
+ private final InsetsSource[] mSources = new InsetsSource[SIZE];
/**
* The frame of the display these sources are relative to.
@@ -804,7 +804,7 @@
public void writeToParcel(Parcel dest, int flags) {
mDisplayFrame.writeToParcel(dest, flags);
mDisplayCutout.writeToParcel(dest, flags);
- dest.writeParcelableArray(mSources, 0);
+ dest.writeTypedArray(mSources, 0 /* parcelableFlags */);
dest.writeTypedObject(mRoundedCorners, flags);
}
@@ -820,9 +820,9 @@
};
public void readFromParcel(Parcel in) {
- mDisplayFrame.set(Rect.CREATOR.createFromParcel(in));
- mDisplayCutout.set(DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in));
- mSources = in.readParcelableArray(null, InsetsSource.class);
+ mDisplayFrame.readFromParcel(in);
+ mDisplayCutout.readFromParcel(in);
+ in.readTypedArray(mSources, InsetsSource.CREATOR);
mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
}
diff --git a/core/java/android/view/ScrollCaptureCallback.java b/core/java/android/view/ScrollCaptureCallback.java
index d3aad2c..1688616 100644
--- a/core/java/android/view/ScrollCaptureCallback.java
+++ b/core/java/android/view/ScrollCaptureCallback.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.UiThread;
import android.graphics.Rect;
+import android.os.CancellationSignal;
import java.util.function.Consumer;
@@ -58,8 +59,6 @@
* @see View#setScrollCaptureHint(int)
* @see View#setScrollCaptureCallback(ScrollCaptureCallback)
* @see Window#registerScrollCaptureCallback(ScrollCaptureCallback)
- *
- * @hide
*/
@UiThread
public interface ScrollCaptureCallback {
@@ -68,80 +67,84 @@
* The system is searching for the appropriate scrolling container to capture and would like to
* know the size and position of scrolling content handled by this callback.
* <p>
- * Implementations should inset {@code containingViewBounds} to cover only the area within the
- * containing view where scrolling content may be positioned. This should cover only the content
- * which tracks with scrolling movement.
+ * To determine scroll bounds, an implementation should inset the visible bounds of the
+ * containing view to cover only the area where scrolling content may be positioned. This
+ * should cover only the content which tracks with scrolling movement.
* <p>
- * Return the updated rectangle to {@code resultConsumer}. If for any reason the scrolling
- * content is not available to capture, a {@code null} rectangle may be returned, and this view
- * will be excluded as the target for this request.
+ * Return the updated rectangle to {@link Consumer#accept onReady.accept}. If for any reason the
+ * scrolling content is not available to capture, a empty rectangle may be returned which will
+ * exclude this view from consideration.
* <p>
- * Responses received after XXXms will be discarded.
- * <p>
- * TODO: finalize timeout
+ * This request may be cancelled via the provided {@link CancellationSignal}. When this happens,
+ * any future call to {@link Consumer#accept onReady.accept} will have no effect and this
+ * content will be omitted from the search results.
*
- * @param onReady consumer for the updated rectangle
+ * @param signal signal to cancel the operation in progress
+ * @param onReady consumer for the updated rectangle
*/
- void onScrollCaptureSearch(@NonNull Consumer<Rect> onReady);
+ void onScrollCaptureSearch(@NonNull CancellationSignal signal, @NonNull Consumer<Rect> onReady);
/**
* Scroll Capture has selected this callback to provide the scrolling image content.
* <p>
- * The onReady signal should be called when ready to begin handling image requests.
+ * {@link Runnable#run onReady.run} should be called when ready to begin handling image
+ * requests.
+ * <p>
+ * This request may be cancelled via the provided {@link CancellationSignal}. When this happens,
+ * any future call to {@link Runnable#run onReady.run} will have no effect and provided session
+ * will not be activated.
+ *
+ * @param session the current session, resources provided by it are valid for use until the
+ * {@link #onScrollCaptureEnd(Runnable) session ends}
+ * @param signal signal to cancel the operation in progress
+ * @param onReady signal used to report completion of the request
*/
- void onScrollCaptureStart(@NonNull ScrollCaptureSession session, @NonNull Runnable onReady);
+ void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Runnable onReady);
/**
* An image capture has been requested from the scrolling content.
* <p>
- * <code>captureArea</code> contains the bounds of the image requested, relative to the
- * rectangle provided by {@link ScrollCaptureCallback#onScrollCaptureSearch}, referred to as
- * {@code scrollBounds}.
- * here.
+ * The requested rectangle describes an area inside the target view, relative to
+ * <code>scrollBounds</code>. The content may be offscreen, above or below the current visible
+ * portion of the target view. To handle the request, render the available portion of this
+ * rectangle to a buffer and return it via the Surface available from {@link
+ * ScrollCaptureSession#getSurface()}.
* <p>
- * A series of requests will step by a constant vertical amount relative to {@code
- * scrollBounds}, moving through the scrolling range of content, above and below the current
- * visible area. The rectangle's vertical position will not account for any scrolling movement
- * since capture started. Implementations therefore must track any scroll position changes and
- * subtract this distance from requests.
+ * Note: Implementations are only required to render the requested content, and may do so into
+ * off-screen buffers without scrolling if they are able.
* <p>
- * To handle a request, the content should be scrolled to maximize the visible area of the
- * requested rectangle. Offset {@code captureArea} again to account for any further scrolling.
+ * The resulting available portion of the request must be computed as a portion of {@code
+ * captureArea}, and sent to signal the operation is complete, using {@link Consumer#accept
+ * onComplete.accept}. If the requested rectangle is partially or fully out of bounds the
+ * resulting portion should be returned. If no portion is available (outside of available
+ * content), then skip sending any buffer and report an empty Rect as result.
* <p>
- * Finally, clip this rectangle against scrollBounds to determine what portion, if any is
- * visible content to capture. If the rectangle is completely clipped, set it to {@link
- * Rect#setEmpty() empty} and skip the next step.
- * <p>
- * Make a copy of {@code captureArea}, transform to window coordinates and draw the window,
- * clipped to this rectangle, into the {@link ScrollCaptureSession#getSurface() surface} at
- * offset (0,0).
- * <p>
- * Finally, return the resulting {@code captureArea} using
- * {@link ScrollCaptureSession#notifyBufferSent}.
- * <p>
- * If the response is not supplied within XXXms, the session will end with a call to {@link
- * #onScrollCaptureEnd}, after which {@code session} is invalid and should be discarded.
- * <p>
- * TODO: finalize timeout
- * <p>
+ * This request may be cancelled via the provided {@link CancellationSignal}. When this happens,
+ * any future call to {@link Consumer#accept onComplete.accept} will be ignored until the next
+ * request.
*
+ * @param session the current session, resources provided by it are valid for use until the
+ * {@link #onScrollCaptureEnd(Runnable) session ends}
+ * @param signal signal to cancel the operation in progress
* @param captureArea the area to capture, a rectangle within {@code scrollBounds}
+ * @param onComplete a consumer for the captured area
*/
- void onScrollCaptureImageRequest(
- @NonNull ScrollCaptureSession session, @NonNull Rect captureArea);
+ void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+ @NonNull Consumer<Rect> onComplete);
/**
* Signals that capture has ended. Implementations should release any temporary resources or
* references to objects in use during the capture. Any resources obtained from the session are
* now invalid and attempts to use them after this point may throw an exception.
* <p>
- * The window should be returned as much as possible to its original state when capture started.
- * At a minimum, the content should be scrolled to its original position.
+ * The window should be returned to its original state when capture started. At a minimum, the
+ * content should be scrolled to its original position.
* <p>
- * <code>onReady</code> should be called when the window should be made visible and
- * interactive. The system will wait up to XXXms for this call before proceeding.
- * <p>
- * TODO: finalize timeout
+ * {@link Runnable#run onReady.run} should be called as soon as possible after the window is
+ * ready for normal interactive use. After the callback (or after a timeout, if not called) the
+ * screenshot tool will be dismissed and the window may become visible to the user at any time.
*
* @param onReady a callback to inform the system that the application has completed any
* cleanup and is ready to become visible
diff --git a/core/java/android/view/ScrollCaptureConnection.java b/core/java/android/view/ScrollCaptureConnection.java
index 0e6cdd1d..3456e01 100644
--- a/core/java/android/view/ScrollCaptureConnection.java
+++ b/core/java/android/view/ScrollCaptureConnection.java
@@ -18,18 +18,23 @@
import static java.util.Objects.requireNonNull;
+import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.UiThread;
-import android.annotation.WorkerThread;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Handler;
+import android.os.CancellationSignal;
+import android.os.ICancellationSignal;
import android.os.RemoteException;
+import android.os.Trace;
import android.util.CloseGuard;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Mediator between a selected scroll capture target view and a remote process.
@@ -41,270 +46,276 @@
public class ScrollCaptureConnection extends IScrollCaptureConnection.Stub {
private static final String TAG = "ScrollCaptureConnection";
- private static final int DEFAULT_TIMEOUT = 1000;
- private final Handler mHandler;
- private ScrollCaptureTarget mSelectedTarget;
- private int mTimeoutMillis = DEFAULT_TIMEOUT;
-
- protected Surface mSurface;
- private IScrollCaptureCallbacks mCallbacks;
-
+ private final Object mLock = new Object();
private final Rect mScrollBounds;
private final Point mPositionInWindow;
private final CloseGuard mCloseGuard;
+ private final Executor mUiThread;
- // The current session instance in use by the callback.
+ private ScrollCaptureCallback mLocal;
+ private IScrollCaptureCallbacks mRemote;
+
private ScrollCaptureSession mSession;
- // Helps manage timeout callbacks registered to handler and aids testing.
- private DelayedAction mTimeoutAction;
+ private CancellationSignal mCancellation;
+
+ private volatile boolean mStarted;
+ private volatile boolean mConnected;
/**
* Constructs a ScrollCaptureConnection.
*
* @param selectedTarget the target the client is controlling
- * @param callbacks the callbacks to reply to system requests
+ * @param remote the callbacks to reply to system requests
*
* @hide
*/
public ScrollCaptureConnection(
+ @NonNull Executor uiThread,
@NonNull ScrollCaptureTarget selectedTarget,
- @NonNull IScrollCaptureCallbacks callbacks) {
+ @NonNull IScrollCaptureCallbacks remote) {
+ mUiThread = requireNonNull(uiThread, "<uiThread> must non-null");
requireNonNull(selectedTarget, "<selectedTarget> must non-null");
- requireNonNull(callbacks, "<callbacks> must non-null");
- final Rect scrollBounds = requireNonNull(selectedTarget.getScrollBounds(),
+ mRemote = requireNonNull(remote, "<callbacks> must non-null");
+ mScrollBounds = requireNonNull(Rect.copyOrNull(selectedTarget.getScrollBounds()),
"target.getScrollBounds() must be non-null to construct a client");
- mSelectedTarget = selectedTarget;
- mHandler = selectedTarget.getContainingView().getHandler();
- mScrollBounds = new Rect(scrollBounds);
+ mLocal = selectedTarget.getCallback();
mPositionInWindow = new Point(selectedTarget.getPositionInWindow());
- mCallbacks = callbacks;
mCloseGuard = new CloseGuard();
mCloseGuard.open("close");
-
- selectedTarget.getContainingView().addOnAttachStateChangeListener(
- new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
-
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- selectedTarget.getContainingView().removeOnAttachStateChangeListener(this);
- endCapture();
- }
- });
+ mConnected = true;
}
- @VisibleForTesting
- public void setTimeoutMillis(int timeoutMillis) {
- mTimeoutMillis = timeoutMillis;
- }
-
- @VisibleForTesting
- public DelayedAction getTimeoutAction() {
- return mTimeoutAction;
- }
-
- private void checkConnected() {
- if (mSelectedTarget == null || mCallbacks == null) {
- throw new IllegalStateException("This client has been disconnected.");
- }
- }
-
- private void checkStarted() {
- if (mSession == null) {
- throw new IllegalStateException("Capture session has not been started!");
- }
- }
-
- @WorkerThread // IScrollCaptureConnection
+ @BinderThread
@Override
- public void startCapture(Surface surface) throws RemoteException {
+ public ICancellationSignal startCapture(Surface surface) throws RemoteException {
checkConnected();
- mSurface = surface;
- scheduleTimeout(mTimeoutMillis, this::onStartCaptureTimeout);
- mSession = new ScrollCaptureSession(mSurface, mScrollBounds, mPositionInWindow, this);
- mHandler.post(() -> mSelectedTarget.getCallback().onScrollCaptureStart(mSession,
- this::onStartCaptureCompleted));
+ if (!surface.isValid()) {
+ throw new RemoteException(new IllegalArgumentException("surface must be valid"));
+ }
+
+ ICancellationSignal cancellation = CancellationSignal.createTransport();
+ mCancellation = CancellationSignal.fromTransport(cancellation);
+ mSession = new ScrollCaptureSession(surface, mScrollBounds, mPositionInWindow);
+
+ Runnable listener =
+ SafeCallback.create(mCancellation, mUiThread, this::onStartCaptureCompleted);
+ // -> UiThread
+ mUiThread.execute(() -> mLocal.onScrollCaptureStart(mSession, mCancellation, listener));
+ return cancellation;
}
@UiThread
private void onStartCaptureCompleted() {
- if (cancelTimeout()) {
- mHandler.post(() -> {
- try {
- mCallbacks.onCaptureStarted();
- } catch (RemoteException e) {
- doShutdown();
- }
- });
+ mStarted = true;
+ try {
+ mRemote.onCaptureStarted();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Shutting down due to error: ", e);
+ close();
}
}
- @UiThread
- private void onStartCaptureTimeout() {
- endCapture();
- }
- @WorkerThread // IScrollCaptureConnection
+ @BinderThread
@Override
- public void requestImage(Rect requestRect) {
+ public ICancellationSignal requestImage(Rect requestRect) throws RemoteException {
+ Trace.beginSection("requestImage");
checkConnected();
checkStarted();
- scheduleTimeout(mTimeoutMillis, this::onRequestImageTimeout);
- // Response is dispatched via ScrollCaptureSession, to onRequestImageCompleted
- mHandler.post(() -> mSelectedTarget.getCallback().onScrollCaptureImageRequest(
- mSession, new Rect(requestRect)));
+
+ ICancellationSignal cancellation = CancellationSignal.createTransport();
+ mCancellation = CancellationSignal.fromTransport(cancellation);
+
+ Consumer<Rect> listener =
+ SafeCallback.create(mCancellation, mUiThread, this::onImageRequestCompleted);
+ // -> UiThread
+ mUiThread.execute(() -> mLocal.onScrollCaptureImageRequest(
+ mSession, mCancellation, new Rect(requestRect), listener));
+ Trace.endSection();
+ return cancellation;
}
@UiThread
- void onRequestImageCompleted(long frameNumber, Rect capturedArea) {
- final Rect finalCapturedArea = new Rect(capturedArea);
- if (cancelTimeout()) {
- mHandler.post(() -> {
- try {
- mCallbacks.onCaptureBufferSent(frameNumber, finalCapturedArea);
- } catch (RemoteException e) {
- doShutdown();
- }
- });
- }
- }
-
- @UiThread
- private void onRequestImageTimeout() {
- endCapture();
- }
-
- @WorkerThread // IScrollCaptureConnection
- @Override
- public void endCapture() {
- if (isStarted()) {
- scheduleTimeout(mTimeoutMillis, this::onEndCaptureTimeout);
- mHandler.post(() ->
- mSelectedTarget.getCallback().onScrollCaptureEnd(this::onEndCaptureCompleted));
- } else {
- disconnect();
- }
- }
-
- private boolean isStarted() {
- return mCallbacks != null && mSelectedTarget != null;
- }
-
- @UiThread
- private void onEndCaptureCompleted() { // onEndCaptureCompleted
- if (cancelTimeout()) {
- doShutdown();
- }
- }
-
- @UiThread
- private void onEndCaptureTimeout() {
- doShutdown();
- }
-
-
- private void doShutdown() {
+ void onImageRequestCompleted(Rect capturedArea) {
try {
- if (mCallbacks != null) {
- mCallbacks.onConnectionClosed();
- }
+ mRemote.onImageRequestCompleted(0, capturedArea);
} catch (RemoteException e) {
- // Ignore
- } finally {
- disconnect();
+ Log.w(TAG, "Shutting down due to error: ", e);
+ close();
}
}
+ @BinderThread
+ @Override
+ public ICancellationSignal endCapture() throws RemoteException {
+ checkConnected();
+ checkStarted();
+
+ ICancellationSignal cancellation = CancellationSignal.createTransport();
+ mCancellation = CancellationSignal.fromTransport(cancellation);
+
+ Runnable listener =
+ SafeCallback.create(mCancellation, mUiThread, this::onEndCaptureCompleted);
+ // -> UiThread
+ mUiThread.execute(() -> mLocal.onScrollCaptureEnd(listener));
+ return cancellation;
+ }
+
+ @UiThread
+ private void onEndCaptureCompleted() {
+ synchronized (mLock) {
+ mStarted = false;
+ try {
+ mRemote.onCaptureEnded();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Shutting down due to error: ", e);
+ close();
+ }
+ }
+ }
+
+ @BinderThread
+ @Override
+ public void close() {
+ if (mStarted) {
+ Log.w(TAG, "close(): capture is still started?! Ending now.");
+
+ // -> UiThread
+ mUiThread.execute(() -> mLocal.onScrollCaptureEnd(() -> { /* ignore */ }));
+ mStarted = false;
+ }
+ disconnect();
+ }
+
/**
* Shuts down this client and releases references to dependent objects. No attempt is made
* to notify the controller, use with caution!
*/
- public void disconnect() {
- if (mSession != null) {
- mSession.disconnect();
+ private void disconnect() {
+ synchronized (mLock) {
mSession = null;
+ mConnected = false;
+ mStarted = false;
+ mRemote = null;
+ mLocal = null;
+ mCloseGuard.close();
}
+ }
- mSelectedTarget = null;
- mCallbacks = null;
+ public boolean isConnected() {
+ return mConnected;
+ }
+
+ public boolean isStarted() {
+ return mStarted;
+ }
+
+ private synchronized void checkConnected() throws RemoteException {
+ synchronized (mLock) {
+ if (!mConnected) {
+ throw new RemoteException(new IllegalStateException("Not connected"));
+ }
+ }
+ }
+
+ private void checkStarted() throws RemoteException {
+ synchronized (mLock) {
+ if (!mStarted) {
+ throw new RemoteException(new IllegalStateException("Not started!"));
+ }
+ }
}
/** @return a string representation of the state of this client */
public String toString() {
return "ScrollCaptureConnection{"
+ + "connected=" + mConnected
+ + ", started=" + mStarted
+ ", session=" + mSession
- + ", selectedTarget=" + mSelectedTarget
- + ", clientCallbacks=" + mCallbacks
+ + ", remote=" + mRemote
+ + ", local=" + mLocal
+ "}";
}
- private boolean cancelTimeout() {
- if (mTimeoutAction != null) {
- return mTimeoutAction.cancel();
- }
- return false;
- }
-
- private void scheduleTimeout(long timeoutMillis, Runnable action) {
- if (mTimeoutAction != null) {
- mTimeoutAction.cancel();
- }
- mTimeoutAction = new DelayedAction(mHandler, timeoutMillis, action);
- }
-
- /** @hide */
@VisibleForTesting
- public static class DelayedAction {
- private final AtomicBoolean mCompleted = new AtomicBoolean();
- private final Object mToken = new Object();
- private final Handler mHandler;
- private final Runnable mAction;
+ public CancellationSignal getCancellation() {
+ return mCancellation;
+ }
- @VisibleForTesting
- public DelayedAction(Handler handler, long timeoutMillis, Runnable action) {
- mHandler = handler;
- mAction = action;
- mHandler.postDelayed(this::onTimeout, mToken, timeoutMillis);
- }
-
- private boolean onTimeout() {
- if (mCompleted.compareAndSet(false, true)) {
- mAction.run();
- return true;
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
}
- return false;
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private static class SafeCallback<T> {
+ private final CancellationSignal mSignal;
+ private final WeakReference<T> mTargetRef;
+ private final Executor mExecutor;
+ private boolean mExecuted;
+
+ protected SafeCallback(CancellationSignal signal, Executor executor, T target) {
+ mSignal = signal;
+ mTargetRef = new WeakReference<>(target);
+ mExecutor = executor;
}
- /**
- * Cause the timeout action to run immediately and mark as timed out.
- *
- * @return true if the timeout was run, false if the timeout had already been canceled
- */
- @VisibleForTesting
- public boolean timeoutNow() {
- return onTimeout();
- }
-
- /**
- * Attempt to cancel the timeout action (such as after a callback is made)
- *
- * @return true if the timeout was canceled and will not run, false if time has expired and
- * the timeout action has or will run momentarily
- */
- public boolean cancel() {
- if (!mCompleted.compareAndSet(false, true)) {
- // Whoops, too late!
- return false;
+ // Provide the target to the consumer to invoke, forward on handler thread ONCE,
+ // and only if noy cancelled, and the target is still available (not collected)
+ protected final void maybeAccept(Consumer<T> targetConsumer) {
+ if (mExecuted) {
+ return;
}
- mHandler.removeCallbacksAndMessages(mToken);
- return true;
+ mExecuted = true;
+ if (mSignal.isCanceled()) {
+ return;
+ }
+ T target = mTargetRef.get();
+ if (target == null) {
+ return;
+ }
+ mExecutor.execute(() -> targetConsumer.accept(target));
+ }
+
+ static Runnable create(CancellationSignal signal, Executor executor, Runnable target) {
+ return new RunnableCallback(signal, executor, target);
+ }
+
+ static <T> Consumer<T> create(CancellationSignal signal, Executor executor,
+ Consumer<T> target) {
+ return new ConsumerCallback<T>(signal, executor, target);
+ }
+ }
+
+ private static final class RunnableCallback extends SafeCallback<Runnable> implements Runnable {
+ RunnableCallback(CancellationSignal signal, Executor executor, Runnable target) {
+ super(signal, executor, target);
+ }
+
+ @Override
+ public void run() {
+ maybeAccept(Runnable::run);
+ }
+ }
+
+ private static final class ConsumerCallback<T> extends SafeCallback<Consumer<T>>
+ implements Consumer<T> {
+ ConsumerCallback(CancellationSignal signal, Executor executor, Consumer<T> target) {
+ super(signal, executor, target);
+ }
+
+ @Override
+ public void accept(T value) {
+ maybeAccept((target) -> target.accept(value));
}
}
}
diff --git a/core/java/android/view/ScrollCaptureResponse.aidl b/core/java/android/view/ScrollCaptureResponse.aidl
new file mode 100644
index 0000000..3de2b80
--- /dev/null
+++ b/core/java/android/view/ScrollCaptureResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.view;
+
+parcelable ScrollCaptureResponse;
diff --git a/core/java/android/view/ScrollCaptureResponse.java b/core/java/android/view/ScrollCaptureResponse.java
new file mode 100644
index 0000000..564113e
--- /dev/null
+++ b/core/java/android/view/ScrollCaptureResponse.java
@@ -0,0 +1,381 @@
+/*
+ * 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.view;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+
+/** @hide */
+@DataClass(genToString = true, genGetters = true)
+public class ScrollCaptureResponse implements Parcelable {
+
+ /** Developer-facing human readable description of the result. */
+ @NonNull
+ private String mDescription = "";
+
+ // Remaining fields are non-null when isConnected() == true
+
+ /** The active connection for a successful result. */
+ @Nullable
+ @DataClass.MaySetToNull
+ private IScrollCaptureConnection mConnection = null;
+
+ /** The bounds of the window within the display */
+ @Nullable
+ private Rect mWindowBounds = null;
+
+ /** The bounds of the scrolling content, in window space. */
+ @Nullable
+ private Rect mBoundsInWindow = null;
+
+ /** The current window title. */
+ @Nullable
+ private String mWindowTitle = null;
+
+ /** Carries additional logging and debugging information when enabled. */
+ @NonNull
+ @DataClass.PluralOf("message")
+ private ArrayList<String> mMessages = new ArrayList<>();
+
+ /** Whether a connection has been returned. */
+ public boolean isConnected() {
+ return mConnection != null;
+ }
+
+
+
+
+ // Code below generated by codegen v1.0.22.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/ScrollCaptureResponse.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ /* package-private */ ScrollCaptureResponse(
+ @NonNull String description,
+ @Nullable IScrollCaptureConnection connection,
+ @Nullable Rect windowBounds,
+ @Nullable Rect boundsInWindow,
+ @Nullable String windowTitle,
+ @NonNull ArrayList<String> messages) {
+ this.mDescription = description;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDescription);
+ this.mConnection = connection;
+ this.mWindowBounds = windowBounds;
+ this.mBoundsInWindow = boundsInWindow;
+ this.mWindowTitle = windowTitle;
+ this.mMessages = messages;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mMessages);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Developer-facing human readable description of the result.
+ */
+ @DataClass.Generated.Member
+ public @NonNull String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * The active connection for a successful result.
+ */
+ @DataClass.Generated.Member
+ public @Nullable IScrollCaptureConnection getConnection() {
+ return mConnection;
+ }
+
+ /**
+ * The bounds of the window within the display
+ */
+ @DataClass.Generated.Member
+ public @Nullable Rect getWindowBounds() {
+ return mWindowBounds;
+ }
+
+ /**
+ * The bounds of the scrolling content, in window space.
+ */
+ @DataClass.Generated.Member
+ public @Nullable Rect getBoundsInWindow() {
+ return mBoundsInWindow;
+ }
+
+ /**
+ * The current window title.
+ */
+ @DataClass.Generated.Member
+ public @Nullable String getWindowTitle() {
+ return mWindowTitle;
+ }
+
+ /**
+ * Carries additional logging and debugging information when enabled.
+ */
+ @DataClass.Generated.Member
+ public @NonNull ArrayList<String> getMessages() {
+ return mMessages;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "ScrollCaptureResponse { " +
+ "description = " + mDescription + ", " +
+ "connection = " + mConnection + ", " +
+ "windowBounds = " + mWindowBounds + ", " +
+ "boundsInWindow = " + mBoundsInWindow + ", " +
+ "windowTitle = " + mWindowTitle + ", " +
+ "messages = " + mMessages +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mConnection != null) flg |= 0x2;
+ if (mWindowBounds != null) flg |= 0x4;
+ if (mBoundsInWindow != null) flg |= 0x8;
+ if (mWindowTitle != null) flg |= 0x10;
+ dest.writeByte(flg);
+ dest.writeString(mDescription);
+ if (mConnection != null) dest.writeStrongInterface(mConnection);
+ if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags);
+ if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags);
+ if (mWindowTitle != null) dest.writeString(mWindowTitle);
+ dest.writeStringList(mMessages);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected ScrollCaptureResponse(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ String description = in.readString();
+ IScrollCaptureConnection connection = (flg & 0x2) == 0 ? null : IScrollCaptureConnection.Stub.asInterface(in.readStrongBinder());
+ Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
+ Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
+ String windowTitle = (flg & 0x10) == 0 ? null : in.readString();
+ ArrayList<String> messages = new ArrayList<>();
+ in.readStringList(messages);
+
+ this.mDescription = description;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDescription);
+ this.mConnection = connection;
+ this.mWindowBounds = windowBounds;
+ this.mBoundsInWindow = boundsInWindow;
+ this.mWindowTitle = windowTitle;
+ this.mMessages = messages;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mMessages);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ScrollCaptureResponse> CREATOR
+ = new Parcelable.Creator<ScrollCaptureResponse>() {
+ @Override
+ public ScrollCaptureResponse[] newArray(int size) {
+ return new ScrollCaptureResponse[size];
+ }
+
+ @Override
+ public ScrollCaptureResponse createFromParcel(@NonNull android.os.Parcel in) {
+ return new ScrollCaptureResponse(in);
+ }
+ };
+
+ /**
+ * A builder for {@link ScrollCaptureResponse}
+ */
+ @SuppressWarnings("WeakerAccess")
+ @DataClass.Generated.Member
+ public static class Builder {
+
+ private @NonNull String mDescription;
+ private @Nullable IScrollCaptureConnection mConnection;
+ private @Nullable Rect mWindowBounds;
+ private @Nullable Rect mBoundsInWindow;
+ private @Nullable String mWindowTitle;
+ private @NonNull ArrayList<String> mMessages;
+
+ private long mBuilderFieldsSet = 0L;
+
+ public Builder() {
+ }
+
+ /**
+ * Developer-facing human readable description of the result.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setDescription(@NonNull String value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x1;
+ mDescription = value;
+ return this;
+ }
+
+ /**
+ * The active connection for a successful result.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setConnection(@Nullable IScrollCaptureConnection value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x2;
+ mConnection = value;
+ return this;
+ }
+
+ /**
+ * The bounds of the window within the display
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setWindowBounds(@NonNull Rect value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x4;
+ mWindowBounds = value;
+ return this;
+ }
+
+ /**
+ * The bounds of the scrolling content, in window space.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setBoundsInWindow(@NonNull Rect value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x8;
+ mBoundsInWindow = value;
+ return this;
+ }
+
+ /**
+ * The current window title.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setWindowTitle(@NonNull String value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x10;
+ mWindowTitle = value;
+ return this;
+ }
+
+ /**
+ * Carries additional logging and debugging information when enabled.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setMessages(@NonNull ArrayList<String> value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x20;
+ mMessages = value;
+ return this;
+ }
+
+ /** @see #setMessages */
+ @DataClass.Generated.Member
+ public @NonNull Builder addMessage(@NonNull String value) {
+ if (mMessages == null) setMessages(new ArrayList<>());
+ mMessages.add(value);
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @NonNull ScrollCaptureResponse build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x40; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mDescription = "";
+ }
+ if ((mBuilderFieldsSet & 0x2) == 0) {
+ mConnection = null;
+ }
+ if ((mBuilderFieldsSet & 0x4) == 0) {
+ mWindowBounds = null;
+ }
+ if ((mBuilderFieldsSet & 0x8) == 0) {
+ mBoundsInWindow = null;
+ }
+ if ((mBuilderFieldsSet & 0x10) == 0) {
+ mWindowTitle = null;
+ }
+ if ((mBuilderFieldsSet & 0x20) == 0) {
+ mMessages = new ArrayList<>();
+ }
+ ScrollCaptureResponse o = new ScrollCaptureResponse(
+ mDescription,
+ mConnection,
+ mWindowBounds,
+ mBoundsInWindow,
+ mWindowTitle,
+ mMessages);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x40) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+
+ @DataClass.Generated(
+ time = 1612282689462L,
+ codegenVersion = "1.0.22",
+ sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java",
+ inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic boolean isConnected()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/view/ScrollCaptureSearchResults.java b/core/java/android/view/ScrollCaptureSearchResults.java
new file mode 100644
index 0000000..3469b9d
--- /dev/null
+++ b/core/java/android/view/ScrollCaptureSearchResults.java
@@ -0,0 +1,271 @@
+/*
+ * 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.view;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.UiThread;
+import android.graphics.Rect;
+import android.os.CancellationSignal;
+import android.util.IndentingPrintWriter;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Collects nodes in the view hierarchy which have been identified as scrollable content.
+ *
+ * @hide
+ */
+@UiThread
+public final class ScrollCaptureSearchResults {
+ private final Executor mExecutor;
+ private final List<ScrollCaptureTarget> mTargets;
+ private final CancellationSignal mCancel;
+
+ private Runnable mOnCompleteListener;
+ private int mCompleted;
+ private boolean mComplete = true;
+
+ public ScrollCaptureSearchResults(Executor executor) {
+ mExecutor = executor;
+ mTargets = new ArrayList<>();
+ mCancel = new CancellationSignal();
+ }
+
+ // Public
+
+ /**
+ * Add the given target to the results.
+ *
+ * @param target the target to consider
+ */
+ public void addTarget(@NonNull ScrollCaptureTarget target) {
+ requireNonNull(target);
+
+ mTargets.add(target);
+ mComplete = false;
+ final ScrollCaptureCallback callback = target.getCallback();
+ final Consumer<Rect> consumer = new SearchRequest(target);
+
+ // Defer so the view hierarchy scan completes first
+ mExecutor.execute(
+ () -> callback.onScrollCaptureSearch(mCancel, consumer));
+ }
+
+ public boolean isComplete() {
+ return mComplete;
+ }
+
+ /**
+ * Provides a callback to be invoked as soon as all responses have been received from all
+ * targets to this point.
+ *
+ * @param onComplete listener to add
+ */
+ public void setOnCompleteListener(Runnable onComplete) {
+ if (mComplete) {
+ onComplete.run();
+ } else {
+ mOnCompleteListener = onComplete;
+ }
+ }
+
+ /**
+ * Indicates whether the search results are empty.
+ *
+ * @return true if no targets have been added
+ */
+ public boolean isEmpty() {
+ return mTargets.isEmpty();
+ }
+
+ /**
+ * Force the results to complete now, cancelling any pending requests and calling a complete
+ * listener if provided.
+ */
+ public void finish() {
+ if (!mComplete) {
+ mCancel.cancel();
+ signalComplete();
+ }
+ }
+
+ private void signalComplete() {
+ mComplete = true;
+ mTargets.sort(PRIORITY_ORDER);
+ if (mOnCompleteListener != null) {
+ mOnCompleteListener.run();
+ mOnCompleteListener = null;
+ }
+ }
+
+ @VisibleForTesting
+ public List<ScrollCaptureTarget> getTargets() {
+ return new ArrayList<>(mTargets);
+ }
+
+ /**
+ * Get the top ranked result out of all completed requests.
+ *
+ * @return the top ranked result
+ */
+ public ScrollCaptureTarget getTopResult() {
+ ScrollCaptureTarget target = mTargets.isEmpty() ? null : mTargets.get(0);
+ return target != null && target.getScrollBounds() != null ? target : null;
+ }
+
+ private class SearchRequest implements Consumer<Rect> {
+ private ScrollCaptureTarget mTarget;
+
+ SearchRequest(ScrollCaptureTarget target) {
+ mTarget = target;
+ }
+
+ @Override
+ public void accept(Rect scrollBounds) {
+ if (mTarget == null || mCancel.isCanceled()) {
+ return;
+ }
+ mExecutor.execute(() -> consume(scrollBounds));
+ }
+
+ private void consume(Rect scrollBounds) {
+ if (mTarget == null || mCancel.isCanceled()) {
+ return;
+ }
+ if (!nullOrEmpty(scrollBounds)) {
+ mTarget.setScrollBounds(scrollBounds);
+ mTarget.updatePositionInWindow();
+ }
+ mCompleted++;
+ mTarget = null;
+
+ // All done?
+ if (mCompleted == mTargets.size()) {
+ signalComplete();
+ }
+ }
+ }
+
+ private static final int AFTER = 1;
+ private static final int BEFORE = -1;
+ private static final int EQUAL = 0;
+
+ static final Comparator<ScrollCaptureTarget> PRIORITY_ORDER = (a, b) -> {
+ if (a == null && b == null) {
+ return 0;
+ } else if (a == null || b == null) {
+ return (a == null) ? 1 : -1;
+ }
+
+ boolean emptyScrollBoundsA = nullOrEmpty(a.getScrollBounds());
+ boolean emptyScrollBoundsB = nullOrEmpty(b.getScrollBounds());
+ if (emptyScrollBoundsA || emptyScrollBoundsB) {
+ if (emptyScrollBoundsA && emptyScrollBoundsB) {
+ return EQUAL;
+ }
+ // Prefer the one with a non-empty scroll bounds
+ if (emptyScrollBoundsA) {
+ return AFTER;
+ }
+ return BEFORE;
+ }
+
+ final View viewA = a.getContainingView();
+ final View viewB = b.getContainingView();
+
+ // Prefer any view with scrollCaptureHint="INCLUDE", over one without
+ // This is an escape hatch for the next rule (descendants first)
+ boolean hintIncludeA = hasIncludeHint(viewA);
+ boolean hintIncludeB = hasIncludeHint(viewB);
+ if (hintIncludeA != hintIncludeB) {
+ return (hintIncludeA) ? BEFORE : AFTER;
+ }
+ // If the views are relatives, prefer the descendant. This allows implementations to
+ // leverage nested scrolling APIs by interacting with the innermost scrollable view (as
+ // would happen with touch input).
+ if (isDescendant(viewA, viewB)) {
+ return BEFORE;
+ }
+ if (isDescendant(viewB, viewA)) {
+ return AFTER;
+ }
+
+ // finally, prefer one with larger scroll bounds
+ int scrollAreaA = area(a.getScrollBounds());
+ int scrollAreaB = area(b.getScrollBounds());
+ return (scrollAreaA >= scrollAreaB) ? BEFORE : AFTER;
+ };
+
+ private static int area(Rect r) {
+ return r.width() * r.height();
+ }
+
+ private static boolean nullOrEmpty(Rect r) {
+ return r == null || r.isEmpty();
+ }
+
+ private static boolean hasIncludeHint(View view) {
+ return (view.getScrollCaptureHint() & View.SCROLL_CAPTURE_HINT_INCLUDE) != 0;
+ }
+
+ /**
+ * Determines if {@code otherView} is a descendant of {@code view}.
+ *
+ * @param view a view
+ * @param otherView another view
+ * @return true if {@code view} is an ancestor of {@code otherView}
+ */
+ private static boolean isDescendant(@NonNull View view, @NonNull View otherView) {
+ if (view == otherView) {
+ return false;
+ }
+ ViewParent otherParent = otherView.getParent();
+ while (otherParent != view && otherParent != null) {
+ otherParent = otherParent.getParent();
+ }
+ return otherParent == view;
+ }
+
+ void dump(IndentingPrintWriter writer) {
+ writer.println("results:");
+ writer.increaseIndent();
+ writer.println("complete: " + isComplete());
+ writer.println("cancelled: " + mCancel.isCanceled());
+ writer.println("targets:");
+ writer.increaseIndent();
+ if (isEmpty()) {
+ writer.println("None");
+ } else {
+ for (int i = 0; i < mTargets.size(); i++) {
+ writer.println("[" + i + "]");
+ writer.increaseIndent();
+ mTargets.get(i).dump(writer);
+ writer.decreaseIndent();
+ }
+ writer.decreaseIndent();
+ }
+ writer.decreaseIndent();
+ }
+}
diff --git a/core/java/android/view/ScrollCaptureSession.java b/core/java/android/view/ScrollCaptureSession.java
index 92617a3..748e7ea 100644
--- a/core/java/android/view/ScrollCaptureSession.java
+++ b/core/java/android/view/ScrollCaptureSession.java
@@ -16,18 +16,15 @@
package android.view;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.graphics.Point;
import android.graphics.Rect;
/**
* A session represents the scope of interaction between a {@link ScrollCaptureCallback} and the
- * system during an active scroll capture operation. During the scope of a session, a callback
- * will receive a series of requests for image data. Resources provided here are valid for use
- * until {@link ScrollCaptureCallback#onScrollCaptureEnd(Runnable)}.
- *
- * @hide
+ * system during an active scroll capture operation.
*/
public class ScrollCaptureSession {
@@ -35,22 +32,27 @@
private final Rect mScrollBounds;
private final Point mPositionInWindow;
- @Nullable
- private ScrollCaptureConnection mConnection;
-
- /** @hide */
- public ScrollCaptureSession(Surface surface, Rect scrollBounds, Point positionInWindow,
- ScrollCaptureConnection connection) {
- mSurface = surface;
- mScrollBounds = scrollBounds;
- mPositionInWindow = positionInWindow;
- mConnection = connection;
+ /**
+ * Constructs a new session instance.
+ *
+ * @param surface the surface to consume generated images
+ * @param scrollBounds the bounds of the capture area within the containing view
+ * @param positionInWindow the offset of scrollBounds within the window
+ */
+ public ScrollCaptureSession(@NonNull Surface surface, @NonNull Rect scrollBounds,
+ @NonNull Point positionInWindow) {
+ mSurface = requireNonNull(surface);
+ mScrollBounds = requireNonNull(scrollBounds);
+ mPositionInWindow = requireNonNull(positionInWindow);
}
/**
* Returns a
* <a href="https://source.android.com/devices/graphics/arch-bq-gralloc">BufferQueue</a> in the
* form of a {@link Surface} for transfer of image buffers.
+ * <p>
+ * The surface is guaranteed to remain {@link Surface#isValid() valid} until the session
+ * {@link ScrollCaptureCallback#onScrollCaptureEnd(Runnable) ends}.
*
* @return the surface for transferring image buffers
* @throws IllegalStateException if the session has been closed
@@ -80,26 +82,4 @@
public Point getPositionInWindow() {
return mPositionInWindow;
}
-
- /**
- * Notify the system that an a buffer has been posted via the getSurface() channel.
- *
- * @param frameNumber the frame number of the queued buffer
- * @param capturedArea the area captured, relative to scroll bounds
- */
- public void notifyBufferSent(long frameNumber, @NonNull Rect capturedArea) {
- if (mConnection != null) {
- mConnection.onRequestImageCompleted(frameNumber, capturedArea);
- }
- }
-
- /**
- * @hide
- */
- public void disconnect() {
- mConnection = null;
- if (mSurface.isValid()) {
- mSurface.release();
- }
- }
}
diff --git a/core/java/android/view/ScrollCaptureTarget.java b/core/java/android/view/ScrollCaptureTarget.java
index f3fcabb..4fd4889 100644
--- a/core/java/android/view/ScrollCaptureTarget.java
+++ b/core/java/android/view/ScrollCaptureTarget.java
@@ -22,14 +22,16 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.CancellationSignal;
import com.android.internal.util.FastMath;
+import java.io.PrintWriter;
+import java.util.function.Consumer;
+
/**
* A target collects the set of contextual information for a ScrollCaptureHandler discovered during
* a {@link View#dispatchScrollCaptureSearch scroll capture search}.
- *
- * @hide
*/
public final class ScrollCaptureTarget {
private final View mContainingView;
@@ -41,7 +43,6 @@
private final float[] mTmpFloatArr = new float[2];
private final Matrix mMatrixViewLocalToWindow = new Matrix();
- private final Rect mTmpRect = new Rect();
public ScrollCaptureTarget(@NonNull View scrollTarget, @NonNull Rect localVisibleRect,
@NonNull Point positionInWindow, @NonNull ScrollCaptureCallback callback) {
@@ -52,7 +53,10 @@
mPositionInWindow = positionInWindow;
}
- /** @return the hint that the {@code containing view} had during the scroll capture search */
+ /**
+ * @return the hint that the {@code containing view} had during the scroll capture search
+ * @see View#getScrollCaptureHint()
+ */
@View.ScrollCaptureHint
public int getHint() {
return mHint;
@@ -71,8 +75,7 @@
}
/**
- * Returns the un-clipped, visible bounds of the containing view during the scroll capture
- * search. This is used to determine on-screen area to assist in selecting the primary target.
+ * Returns the visible bounds of the containing view.
*
* @return the visible bounds of the {@code containing view} in view-local coordinates
*/
@@ -81,13 +84,17 @@
return mLocalVisibleRect;
}
- /** @return the position of the {@code containing view} within the window */
+ /** @return the position of the visible bounds of the containing view within the window */
@NonNull
public Point getPositionInWindow() {
return mPositionInWindow;
}
- /** @return the {@code scroll bounds} for this {@link ScrollCaptureCallback callback} */
+ /**
+ * @return the {@code scroll bounds} for this {@link ScrollCaptureCallback callback}
+ *
+ * @see ScrollCaptureCallback#onScrollCaptureSearch(CancellationSignal, Consumer)
+ */
@Nullable
public Rect getScrollBounds() {
return mScrollBounds;
@@ -119,8 +126,8 @@
}
/**
- * Refresh the value of {@link #mLocalVisibleRect} and {@link #mPositionInWindow} based on the
- * current state of the {@code containing view}.
+ * Refresh the local visible bounds and it's offset within the window, based on the current
+ * state of the {@code containing view}.
*/
@UiThread
public void updatePositionInWindow() {
@@ -132,4 +139,27 @@
roundIntoPoint(mPositionInWindow, mTmpFloatArr);
}
+ public String toString() {
+ return "ScrollCaptureTarget{" + "view=" + mContainingView
+ + ", callback=" + mCallback
+ + ", scrollBounds=" + mScrollBounds
+ + ", localVisibleRect=" + mLocalVisibleRect
+ + ", positionInWindow=" + mPositionInWindow
+ + "}";
+ }
+
+ void dump(@NonNull PrintWriter writer) {
+ View view = getContainingView();
+ writer.println("view: " + view);
+ writer.println("hint: " + mHint);
+ writer.println("callback: " + mCallback);
+ writer.println("scrollBounds: "
+ + (mScrollBounds == null ? "null" : mScrollBounds.toShortString()));
+ Point inWindow = getPositionInWindow();
+ writer.println("positionInWindow: "
+ + ((inWindow == null) ? "null" : "[" + inWindow.x + "," + inWindow.y + "]"));
+ Rect localVisible = getLocalVisibleRect();
+ writer.println("localVisibleRect: "
+ + (localVisible == null ? "null" : localVisible.toShortString()));
+ }
}
diff --git a/core/java/android/view/ScrollCaptureTargetResolver.java b/core/java/android/view/ScrollCaptureTargetResolver.java
deleted file mode 100644
index e4316bb..0000000
--- a/core/java/android/view/ScrollCaptureTargetResolver.java
+++ /dev/null
@@ -1,337 +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.
- */
-
-package android.view;
-
-import android.annotation.AnyThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UiThread;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-
-import java.util.Queue;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
-
-/**
- * Queries additional state from a list of {@link ScrollCaptureTarget targets} via asynchronous
- * callbacks, then aggregates and reduces the target list to a single target, or null if no target
- * is suitable.
- * <p>
- * The rules for selection are (in order):
- * <ul>
- * <li>prefer getScrollBounds(): non-empty
- * <li>prefer View.getScrollCaptureHint == SCROLL_CAPTURE_HINT_INCLUDE
- * <li>prefer descendants before parents
- * <li>prefer larger area for getScrollBounds() (clipped to view bounds)
- * </ul>
- *
- * <p>
- * All calls to {@link ScrollCaptureCallback#onScrollCaptureSearch} are made on the main thread,
- * with results are queued and consumed to the main thread as well.
- *
- * @see #start(Handler, long, Consumer)
- *
- * @hide
- */
-@UiThread
-public class ScrollCaptureTargetResolver {
- private static final String TAG = "ScrollCaptureTargetRes";
-
- private final Object mLock = new Object();
-
- private final Queue<ScrollCaptureTarget> mTargets;
- private Handler mHandler;
- private long mTimeLimitMillis;
-
- private Consumer<ScrollCaptureTarget> mWhenComplete;
- private int mPendingBoundsRequests;
- private long mDeadlineMillis;
-
- private ScrollCaptureTarget mResult;
- private boolean mFinished;
-
- private boolean mStarted;
-
- private static int area(Rect r) {
- return r.width() * r.height();
- }
-
- private static boolean nullOrEmpty(Rect r) {
- return r == null || r.isEmpty();
- }
-
- /**
- * Binary operator which selects the best {@link ScrollCaptureTarget}.
- */
- private static ScrollCaptureTarget chooseTarget(ScrollCaptureTarget a, ScrollCaptureTarget b) {
- if (a == null && b == null) {
- return null;
- } else if (a == null || b == null) {
- ScrollCaptureTarget c = (a == null) ? b : a;
- return c;
- }
-
- boolean emptyScrollBoundsA = nullOrEmpty(a.getScrollBounds());
- boolean emptyScrollBoundsB = nullOrEmpty(b.getScrollBounds());
- if (emptyScrollBoundsA || emptyScrollBoundsB) {
- if (emptyScrollBoundsA && emptyScrollBoundsB) {
- // Both have an empty or null scrollBounds
- Log.d(TAG, "chooseTarget: (both have empty or null bounds) return " + null);
- return null;
- }
- // Prefer the one with a non-empty scroll bounds
- if (emptyScrollBoundsA) {
- Log.d(TAG, "chooseTarget: (a has empty or null bounds) return " + b);
- return b;
- }
- Log.d(TAG, "chooseTarget: (b has empty or null bounds) return " + a);
- return a;
- }
-
- final View viewA = a.getContainingView();
- final View viewB = b.getContainingView();
-
- // Prefer any view with scrollCaptureHint="INCLUDE", over one without
- // This is an escape hatch for the next rule (descendants first)
- boolean hintIncludeA = hasIncludeHint(viewA);
- boolean hintIncludeB = hasIncludeHint(viewB);
- if (hintIncludeA != hintIncludeB) {
- ScrollCaptureTarget c = (hintIncludeA) ? a : b;
- Log.d(TAG, "chooseTarget: (has hint=INCLUDE) return " + c);
- return c;
- }
-
- // If the views are relatives, prefer the descendant. This allows implementations to
- // leverage nested scrolling APIs by interacting with the innermost scrollable view (as
- // would happen with touch input).
- if (isDescendant(viewA, viewB)) {
- Log.d(TAG, "chooseTarget: (b is descendant of a) return " + b);
- return b;
- }
- if (isDescendant(viewB, viewA)) {
- Log.d(TAG, "chooseTarget: (a is descendant of b) return " + a);
- return a;
- }
-
- // finally, prefer one with larger scroll bounds
- int scrollAreaA = area(a.getScrollBounds());
- int scrollAreaB = area(b.getScrollBounds());
- ScrollCaptureTarget c = (scrollAreaA >= scrollAreaB) ? a : b;
- Log.d(TAG, "chooseTarget: return " + c);
- return c;
- }
-
- /**
- * Creates an instance to query and filter {@code target}.
- *
- * @param targets a list of {@link ScrollCaptureTarget} as collected by {@link
- * View#dispatchScrollCaptureSearch}.
- * @see #start(Handler, long, Consumer)
- */
- public ScrollCaptureTargetResolver(Queue<ScrollCaptureTarget> targets) {
- mTargets = targets;
- }
-
- void checkThread() {
- if (mHandler.getLooper() != Looper.myLooper()) {
- throw new IllegalStateException("Called from wrong thread! ("
- + Thread.currentThread().getName() + ")");
- }
- }
-
- /**
- * Blocks until a result is returned (after completion or timeout).
- * <p>
- * For testing only. Normal usage should receive a callback after calling {@link #start}.
- */
- @VisibleForTesting
- public ScrollCaptureTarget waitForResult() throws InterruptedException {
- synchronized (mLock) {
- while (!mFinished) {
- mLock.wait();
- }
- }
- return mResult;
- }
-
- private void supplyResult(ScrollCaptureTarget target) {
- checkThread();
- if (mFinished) {
- return;
- }
- mResult = chooseTarget(mResult, target);
- boolean finish = mPendingBoundsRequests == 0
- || SystemClock.uptimeMillis() >= mDeadlineMillis;
- if (finish) {
- mPendingBoundsRequests = 0;
- mWhenComplete.accept(mResult);
- synchronized (mLock) {
- mFinished = true;
- mLock.notify();
- }
- mWhenComplete = null;
- }
- }
-
- /**
- * Asks all targets for {@link ScrollCaptureCallback#onScrollCaptureSearch(Consumer)
- * scrollBounds}, and selects the primary target according to the {@link
- * #chooseTarget} function.
- *
- * @param timeLimitMillis the amount of time to wait for all responses before delivering the top
- * result
- * @param resultConsumer the consumer to receive the primary target
- */
- @AnyThread
- public void start(Handler uiHandler, long timeLimitMillis,
- Consumer<ScrollCaptureTarget> resultConsumer) {
- synchronized (mLock) {
- if (mStarted) {
- throw new IllegalStateException("already started!");
- }
- if (timeLimitMillis < 0) {
- throw new IllegalArgumentException("Time limit must be positive");
- }
- mHandler = uiHandler;
- mTimeLimitMillis = timeLimitMillis;
- mWhenComplete = resultConsumer;
- if (mTargets.isEmpty()) {
- mHandler.post(() -> supplyResult(null));
- return;
- }
- mStarted = true;
- uiHandler.post(this::run);
- }
- }
-
- private void run() {
- checkThread();
-
- mPendingBoundsRequests = mTargets.size();
- for (ScrollCaptureTarget target : mTargets) {
- queryTarget(target);
- }
- mDeadlineMillis = SystemClock.uptimeMillis() + mTimeLimitMillis;
- mHandler.postAtTime(mTimeoutRunnable, mDeadlineMillis);
- }
-
- private final Runnable mTimeoutRunnable = () -> {
- checkThread();
- supplyResult(null);
- };
-
- /**
- * Adds a target to the list and requests {@link ScrollCaptureCallback#onScrollCaptureSearch}
- * scrollBounds} from it. Results are returned by a call to {@link #onScrollBoundsProvided}.
- *
- * @param target the target to add
- */
- @UiThread
- private void queryTarget(@NonNull ScrollCaptureTarget target) {
- checkThread();
- final ScrollCaptureCallback callback = target.getCallback();
- // from the UI thread, request scroll bounds
- callback.onScrollCaptureSearch(
- // allow only one callback to onReady.accept():
- new SingletonConsumer<Rect>(
- // Queue and consume on the UI thread
- ((scrollBounds) -> mHandler.post(
- () -> onScrollBoundsProvided(target, scrollBounds)))));
- }
-
- @UiThread
- private void onScrollBoundsProvided(ScrollCaptureTarget target, @Nullable Rect scrollBounds) {
- checkThread();
- if (mFinished) {
- return;
- }
-
- // Record progress.
- mPendingBoundsRequests--;
-
- // Remove the timeout.
- mHandler.removeCallbacks(mTimeoutRunnable);
-
- boolean doneOrTimedOut = mPendingBoundsRequests == 0
- || SystemClock.uptimeMillis() >= mDeadlineMillis;
-
- final View containingView = target.getContainingView();
- if (!nullOrEmpty(scrollBounds) && containingView.isAggregatedVisible()) {
- target.updatePositionInWindow();
- target.setScrollBounds(scrollBounds);
- supplyResult(target);
- }
-
- if (!mFinished) {
- // Reschedule the timeout.
- mHandler.postAtTime(mTimeoutRunnable, mDeadlineMillis);
- }
- }
-
- private static boolean hasIncludeHint(View view) {
- return (view.getScrollCaptureHint() & View.SCROLL_CAPTURE_HINT_INCLUDE) != 0;
- }
-
- /**
- * Determines if {@code otherView} is a descendant of {@code view}.
- *
- * @param view a view
- * @param otherView another view
- * @return true if {@code view} is an ancestor of {@code otherView}
- */
- private static boolean isDescendant(@NonNull View view, @NonNull View otherView) {
- if (view == otherView) {
- return false;
- }
- ViewParent otherParent = otherView.getParent();
- while (otherParent != view && otherParent != null) {
- otherParent = otherParent.getParent();
- }
- return otherParent == view;
- }
-
- /**
- * A safe wrapper for a consumer callbacks intended to accept a single value. It ensures
- * that the receiver of the consumer does not retain a reference to {@code target} after use nor
- * cause race conditions by invoking {@link Consumer#accept accept} more than once.
- */
- static class SingletonConsumer<T> implements Consumer<T> {
- final AtomicReference<Consumer<T>> mAtomicRef;
-
- /**
- * @param target the target consumer
- **/
- SingletonConsumer(Consumer<T> target) {
- mAtomicRef = new AtomicReference<>(target);
- }
-
- @Override
- public void accept(T t) {
- final Consumer<T> consumer = mAtomicRef.getAndSet(null);
- if (consumer != null) {
- consumer.accept(t);
- }
- }
- }
-}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 0832578..03dd100 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -3504,64 +3504,4 @@
public static Transaction getGlobalTransaction() {
return sGlobalTransaction;
}
-
- /**
- * Wrapper for sending blur data to SurfaceFlinger.
- * @hide
- */
- public static final class BlurRegion {
- public int blurRadius;
- public float cornerRadiusTL;
- public float cornerRadiusTR;
- public float cornerRadiusBL;
- public float cornerRadiusBR;
- public float alpha = 1;
- public boolean visible = true;
- public final Rect rect = new Rect();
-
- private final float[] mFloatArray = new float[10];
-
- public BlurRegion() {
- }
-
- public BlurRegion(BlurRegion other) {
- rect.set(other.rect);
- blurRadius = other.blurRadius;
- alpha = other.alpha;
- cornerRadiusTL = other.cornerRadiusTL;
- cornerRadiusTR = other.cornerRadiusTR;
- cornerRadiusBL = other.cornerRadiusBL;
- cornerRadiusBR = other.cornerRadiusBR;
- }
-
- /**
- * Serializes this class into a float array that's more JNI friendly.
- */
- public float[] toFloatArray() {
- mFloatArray[0] = blurRadius;
- mFloatArray[1] = alpha;
- mFloatArray[2] = rect.left;
- mFloatArray[3] = rect.top;
- mFloatArray[4] = rect.right;
- mFloatArray[5] = rect.bottom;
- mFloatArray[6] = cornerRadiusTL;
- mFloatArray[7] = cornerRadiusTR;
- mFloatArray[8] = cornerRadiusBL;
- mFloatArray[9] = cornerRadiusBR;
- return mFloatArray;
- }
-
- @Override
- public String toString() {
- return "BlurRegion{"
- + "blurRadius=" + blurRadius
- + ", corners={" + cornerRadiusTL
- + "," + cornerRadiusTR
- + "," + cornerRadiusBL
- + "," + cornerRadiusBR
- + "}, alpha=" + alpha
- + ", rect=" + rect
- + "}";
- }
- }
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ec7e4c1..9688c67 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -544,6 +544,7 @@
// recreate this Surface, so only release it when we are fully
// detached.
if (mSurfacePackage != null) {
+ mTmpTransaction.reparent(mSurfacePackage.getSurfaceControl(), null).apply();
mSurfacePackage.release();
mSurfacePackage = null;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3789324..ebef464 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -184,10 +184,10 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Queue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -1484,7 +1484,6 @@
*
* @see #getScrollCaptureHint()
* @see #setScrollCaptureHint(int)
- * @hide
*/
public static final int SCROLL_CAPTURE_HINT_AUTO = 0;
@@ -1495,7 +1494,6 @@
*
* @see #getScrollCaptureHint()
* @see #setScrollCaptureHint(int)
- * @hide
*/
public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1;
@@ -1506,7 +1504,6 @@
*
* @see #getScrollCaptureHint()
* @see #setScrollCaptureHint(int)
- * @hide
*/
public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2;
@@ -1517,7 +1514,6 @@
*
* @see #getScrollCaptureHint()
* @see #setScrollCaptureHint(int)
- * @hide
*/
public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4;
@@ -30053,8 +30049,6 @@
* Returns the current scroll capture hint for this view.
*
* @return the current scroll capture hint
- *
- * @hide
*/
@ScrollCaptureHint
public int getScrollCaptureHint() {
@@ -30067,8 +30061,6 @@
* scroll capture targets.
*
* @param hint the scrollCaptureHint flags value to set
- *
- * @hide
*/
public void setScrollCaptureHint(@ScrollCaptureHint int hint) {
mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK;
@@ -30088,10 +30080,8 @@
* setting a custom callback to help ensure it is selected as the target.
*
* @param callback the new callback to assign
- *
- * @hide
*/
- public void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) {
+ public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) {
getListenerInfo().mScrollCaptureCallback = callback;
}
@@ -30110,29 +30100,54 @@
}
/**
+ * Dispatch a scroll capture search request down the view hierarchy.
+ *
+ * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to
+ * the parent
+ * @param windowOffset the offset of this view within the window
+ * @param targets accepts potential scroll capture targets; {@link Consumer#accept
+ * results.accept} may be called zero or more times on the calling
+ * thread before onScrollCaptureSearch returns
+ */
+ public void dispatchScrollCaptureSearch(
+ @NonNull Rect localVisibleRect, @NonNull Point windowOffset,
+ @NonNull Consumer<ScrollCaptureTarget> targets) {
+ onScrollCaptureSearch(localVisibleRect, windowOffset, targets);
+ }
+
+ /**
* Called when scroll capture is requested, to search for appropriate content to scroll. If
* applicable, this view adds itself to the provided list for consideration, subject to the
* flags set by {@link #setScrollCaptureHint}.
*
* @param localVisibleRect the local visible rect of this view
* @param windowOffset the offset of localVisibleRect within the window
- * @param targets a queue which collects potential targets
- *
+ * @param targets accepts potential scroll capture targets; {@link Consumer#accept
+ * results.accept} may be called zero or more times on the calling
+ * thread before onScrollCaptureSearch returns
* @throws IllegalStateException if this view is not attached to a window
- * @hide
*/
- public void dispatchScrollCaptureSearch(@NonNull Rect localVisibleRect,
- @NonNull Point windowOffset, @NonNull Queue<ScrollCaptureTarget> targets) {
+ public void onScrollCaptureSearch(@NonNull Rect localVisibleRect,
+ @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) {
int hint = getScrollCaptureHint();
if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) {
return;
}
+ boolean rectIsVisible = true;
+
+ // Apply clipBounds if present.
+ if (mClipBounds != null) {
+ rectIsVisible = localVisibleRect.intersect(mClipBounds);
+ }
+ if (!rectIsVisible) {
+ return;
+ }
// Get a callback provided by the framework, library or application.
ScrollCaptureCallback callback =
(mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback;
- // Try internal support for standard scrolling containers.
+ // Try framework support for standard scrolling containers.
if (callback == null) {
callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset);
}
@@ -30142,7 +30157,7 @@
// Add to the list for consideration
Point offset = new Point(windowOffset.x, windowOffset.y);
Rect rect = new Rect(localVisibleRect);
- targets.add(new ScrollCaptureTarget(this, rect, offset, callback));
+ targets.accept(new ScrollCaptureTarget(this, rect, offset, callback));
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 37bea58..38a5937 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -77,7 +77,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Queue;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -7463,92 +7463,73 @@
}
/**
- * Offsets the given rectangle in parent's local coordinates into child's coordinate space
- * and clips the result to the child View's bounds, padding and clipRect if appropriate. If the
- * resulting rectangle is not empty, the request is forwarded to the child.
- * <p>
- * Note: This method does not account for any static View transformations which may be
- * applied to the child view.
- *
- * @param child the child to dispatch to
- * @param localVisibleRect the visible (clipped) area of this ViewGroup, in local coordinates
- * @param windowOffset the offset of localVisibleRect within the window
- * @param targets a queue to collect located targets
- */
- private void dispatchTransformedScrollCaptureSearch(View child, Rect localVisibleRect,
- Point windowOffset, Queue<ScrollCaptureTarget> targets) {
-
- // copy local visible rect for modification and dispatch
- final Rect childVisibleRect = getTempRect();
- childVisibleRect.set(localVisibleRect);
-
- // transform to child coords
- final Point childWindowOffset = getTempPoint();
- childWindowOffset.set(windowOffset.x, windowOffset.y);
-
- final int dx = child.mLeft - mScrollX;
- final int dy = child.mTop - mScrollY;
-
- childVisibleRect.offset(-dx, -dy);
- childWindowOffset.offset(dx, dy);
-
- boolean rectIsVisible = true;
- final int width = mRight - mLeft;
- final int height = mBottom - mTop;
-
- // Clip to child bounds
- if (getClipChildren()) {
- rectIsVisible = childVisibleRect.intersect(0, 0, child.getWidth(), child.getHeight());
- }
-
- // Clip to child padding.
- if (rectIsVisible && (child instanceof ViewGroup)
- && ((ViewGroup) child).getClipToPadding()) {
- rectIsVisible = childVisibleRect.intersect(
- child.mPaddingLeft, child.mPaddingTop,
- child.getWidth() - child.mPaddingRight,
- child.getHeight() - child.mPaddingBottom);
- }
- // Clip to child clipBounds.
- if (rectIsVisible && child.mClipBounds != null) {
- rectIsVisible = childVisibleRect.intersect(child.mClipBounds);
- }
- if (rectIsVisible) {
- child.dispatchScrollCaptureSearch(childVisibleRect, childWindowOffset, targets);
- }
- }
-
- /**
* Handle the scroll capture search request by checking this view if applicable, then to each
* child view.
*
* @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to
* the parent
* @param windowOffset the offset of this view within the window
- * @param targets the collected list of scroll capture targets
- *
- * @hide
+ * @param targets accepts potential scroll capture targets; {@link Consumer#accept
+ * results.accept} may be called zero or more times on the calling
+ * thread before onScrollCaptureSearch returns
*/
@Override
public void dispatchScrollCaptureSearch(
@NonNull Rect localVisibleRect, @NonNull Point windowOffset,
- @NonNull Queue<ScrollCaptureTarget> targets) {
+ @NonNull Consumer<ScrollCaptureTarget> targets) {
+
+ // copy local visible rect for modification and dispatch
+ final Rect rect = getTempRect();
+ rect.set(localVisibleRect);
+
+ if (getClipToPadding()) {
+ rect.inset(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
+ }
// Dispatch to self first.
super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets);
- // Then dispatch to children, if not excluding descendants.
- if ((getScrollCaptureHint() & SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) == 0) {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- // Only visible views can be captured.
- if (child.getVisibility() != View.VISIBLE) {
- continue;
- }
- // Transform to child coords and dispatch
- dispatchTransformedScrollCaptureSearch(child, localVisibleRect, windowOffset,
- targets);
+ // Skip children if descendants excluded.
+ if ((getScrollCaptureHint() & SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) != 0) {
+ return;
+ }
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ // Only visible views can be captured.
+ if (child.getVisibility() != View.VISIBLE) {
+ continue;
+ }
+ // Offset the given rectangle (in parent's local coordinates) into child's coordinate
+ // space and clip the result to the child View's bounds, padding and clipRect as needed.
+ // If the resulting rectangle is not empty, the request is forwarded to the child.
+
+ // copy local visible rect for modification and dispatch
+ final Rect childVisibleRect = getTempRect();
+ childVisibleRect.set(localVisibleRect);
+
+ // transform to child coords
+ final Point childWindowOffset = getTempPoint();
+ childWindowOffset.set(windowOffset.x, windowOffset.y);
+
+ final int dx = child.mLeft - mScrollX;
+ final int dy = child.mTop - mScrollY;
+
+ childVisibleRect.offset(-dx, -dy);
+ childWindowOffset.offset(dx, dy);
+
+ boolean rectIsVisible = true;
+
+ // Clip to child bounds
+ if (getClipChildren()) {
+ rectIsVisible = childVisibleRect.intersect(0, 0, child.getWidth(),
+ child.getHeight());
+ }
+
+ // Clip to child padding.
+ if (rectIsVisible) {
+ child.dispatchScrollCaptureSearch(childVisibleRect, childWindowOffset, targets);
}
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1abcb15..f8e65bd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -141,6 +141,7 @@
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.LongArray;
import android.util.MergedConfiguration;
@@ -202,6 +203,7 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
@@ -274,6 +276,11 @@
*/
private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2;
+ /**
+ * Maximum time to wait for {@link View#dispatchScrollCaptureSearch} to complete.
+ */
+ private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
@@ -668,8 +675,6 @@
private final InsetsController mInsetsController;
private final ImeFocusController mImeFocusController;
- private ScrollCaptureConnection mScrollCaptureConnection;
-
private boolean mIsSurfaceOpaque;
private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator =
@@ -683,12 +688,6 @@
return mImeFocusController;
}
- /** @return The current {@link ScrollCaptureConnection} for this instance, if any is active. */
- @Nullable
- public ScrollCaptureConnection getScrollCaptureConnection() {
- return mScrollCaptureConnection;
- }
-
private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();
private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
@@ -730,6 +729,8 @@
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
+ private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
+
/**
* Increment this value when the surface has been replaced.
*/
@@ -817,6 +818,8 @@
mImeFocusController = new ImeFocusController(this);
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
mFastScrollSoundEffectsEnabled = audioManager.areNavigationRepeatSoundEffectsEnabled();
+
+ mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -3966,11 +3969,12 @@
}
private void addFrameCallbackIfNeeded() {
- boolean nextDrawUseBlastSync = mNextDrawUseBlastSync;
- boolean hasBlur = mBlurRegionAggregator.hasRegions();
- boolean reportNextDraw = mReportNextDraw;
+ final boolean nextDrawUseBlastSync = mNextDrawUseBlastSync;
+ final boolean reportNextDraw = mReportNextDraw;
+ final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
+ final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
- if (!nextDrawUseBlastSync && !reportNextDraw && !hasBlur) {
+ if (!nextDrawUseBlastSync && !reportNextDraw && !needsCallbackForBlur) {
return;
}
@@ -3978,18 +3982,22 @@
Log.d(mTag, "Creating frameDrawingCallback"
+ " nextDrawUseBlastSync=" + nextDrawUseBlastSync
+ " reportNextDraw=" + reportNextDraw
- + " hasBlur=" + hasBlur);
+ + " hasBlurUpdates=" + hasBlurUpdates);
}
- // The callback will run on a worker thread pool from the render thread.
+ final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
+ needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
+
+ // The callback will run on the render thread.
HardwareRenderer.FrameDrawingCallback frameDrawingCallback = frame -> {
if (DEBUG_BLAST) {
Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "."
+ " Creating transactionCompleteCallback=" + nextDrawUseBlastSync);
}
- if (hasBlur) {
- mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame);
+ if (needsCallbackForBlur) {
+ mBlurRegionAggregator
+ .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates);
}
if (mBlastBufferQueue == null) {
@@ -9223,9 +9231,9 @@
* Collect and include any ScrollCaptureCallback instances registered with the window.
*
* @see #addScrollCaptureCallback(ScrollCaptureCallback)
- * @param targets the search queue for targets
+ * @param results an object to collect the results of the search
*/
- private void collectRootScrollCaptureTargets(Queue<ScrollCaptureTarget> targets) {
+ private void collectRootScrollCaptureTargets(ScrollCaptureSearchResults results) {
if (mRootScrollCaptureCallbacks == null) {
return;
}
@@ -9233,26 +9241,45 @@
// Add to the list for consideration
Point offset = new Point(mView.getLeft(), mView.getTop());
Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight());
- targets.add(new ScrollCaptureTarget(mView, rect, offset, cb));
+ results.addTarget(new ScrollCaptureTarget(mView, rect, offset, cb));
}
}
/**
- * Handles an inbound request for scroll capture from the system. If a client is not already
- * active, a search will be dispatched through the view tree to locate scrolling content.
+ * Update the timeout for scroll capture requests. Only affects this view root.
+ * The default value is {@link #SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS}.
+ *
+ * @param timeMillis the new timeout in milliseconds
+ */
+ public void setScrollCaptureRequestTimeout(int timeMillis) {
+ mScrollCaptureRequestTimeout = timeMillis;
+ }
+
+ /**
+ * Get the current timeout for scroll capture requests.
+ *
+ * @return the timeout in milliseconds
+ */
+ public long getScrollCaptureRequestTimeout() {
+ return mScrollCaptureRequestTimeout;
+ }
+
+ /**
+ * Handles an inbound request for scroll capture from the system. A search will be
+ * dispatched through the view tree to locate scrolling content.
* <p>
- * Either {@link IScrollCaptureCallbacks#onConnected(IScrollCaptureConnection, Rect,
- * Point)} or {@link IScrollCaptureCallbacks#onUnavailable()} will be returned
- * depending on the results of the search.
+ * A call to {@link IScrollCaptureCallbacks#onScrollCaptureResponse(ScrollCaptureResponse)}
+ * will follow.
*
* @param callbacks to receive responses
- * @see ScrollCaptureTargetResolver
+ * @see ScrollCaptureTargetSelector
*/
public void handleScrollCaptureRequest(@NonNull IScrollCaptureCallbacks callbacks) {
- LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+ ScrollCaptureSearchResults results =
+ new ScrollCaptureSearchResults(mContext.getMainExecutor());
// Window (root) level callbacks
- collectRootScrollCaptureTargets(targetList);
+ collectRootScrollCaptureTargets(results);
// Search through View-tree
View rootView = getView();
@@ -9260,58 +9287,70 @@
Point point = new Point();
Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
getChildVisibleRect(rootView, rect, point);
- rootView.dispatchScrollCaptureSearch(rect, point, targetList);
+ rootView.dispatchScrollCaptureSearch(rect, point, results::addTarget);
}
-
- // No-op path. Scroll capture not offered for this window.
- if (targetList.isEmpty()) {
- dispatchScrollCaptureSearchResult(callbacks, null);
- return;
+ Runnable onComplete = () -> dispatchScrollCaptureSearchResult(callbacks, results);
+ results.setOnCompleteListener(onComplete);
+ if (!results.isComplete()) {
+ mHandler.postDelayed(results::finish, getScrollCaptureRequestTimeout());
}
-
- // Request scrollBounds from each of the targets.
- // Continues with the consumer once all responses are consumed, or the timeout expires.
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetList);
- resolver.start(mHandler, 1000,
- (selected) -> dispatchScrollCaptureSearchResult(callbacks, selected));
}
/** Called by {@link #handleScrollCaptureRequest} when a result is returned */
private void dispatchScrollCaptureSearchResult(
@NonNull IScrollCaptureCallbacks callbacks,
- @Nullable ScrollCaptureTarget selectedTarget) {
+ @NonNull ScrollCaptureSearchResults results) {
- // If timeout or no eligible targets found.
+ ScrollCaptureTarget selectedTarget = results.getTopResult();
+
+ ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
+ response.setWindowTitle(getTitle().toString());
+
+ StringWriter writer = new StringWriter();
+ IndentingPrintWriter pw = new IndentingPrintWriter(writer);
+ results.dump(pw);
+ pw.flush();
+ response.addMessage(writer.toString());
+
if (selectedTarget == null) {
+ response.setDescription("No scrollable targets found in window");
try {
- if (DEBUG_SCROLL_CAPTURE) {
- Log.d(TAG, "scrollCaptureSearch returned no targets available.");
- }
- callbacks.onUnavailable();
+ callbacks.onScrollCaptureResponse(response.build());
} catch (RemoteException e) {
- if (DEBUG_SCROLL_CAPTURE) {
- Log.w(TAG, "Failed to send scroll capture search result.", e);
- }
+ Log.e(TAG, "Failed to send scroll capture search result", e);
}
return;
}
- // Create a client instance and return it to the caller
- mScrollCaptureConnection = new ScrollCaptureConnection(selectedTarget, callbacks);
+ response.setDescription("Connected");
+
+ // Compute area covered by scrolling content within window
+ Rect boundsInWindow = new Rect();
+ View containingView = selectedTarget.getContainingView();
+ containingView.getLocationInWindow(mAttachInfo.mTmpLocation);
+ boundsInWindow.set(selectedTarget.getScrollBounds());
+ boundsInWindow.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
+ response.setBoundsInWindow(boundsInWindow);
+
+ // Compute the area on screen covered by the window
+ Rect boundsOnScreen = new Rect();
+ mView.getLocationOnScreen(mAttachInfo.mTmpLocation);
+ boundsOnScreen.set(0, 0, mView.getWidth(), mView.getHeight());
+ boundsOnScreen.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
+ response.setWindowBounds(boundsOnScreen);
+
+ // Create a connection and return it to the caller
+ ScrollCaptureConnection connection = new ScrollCaptureConnection(
+ mView.getContext().getMainExecutor(), selectedTarget, callbacks);
+ response.setConnection(connection);
+
try {
- if (DEBUG_SCROLL_CAPTURE) {
- Log.d(TAG, "scrollCaptureSearch returning client: " + getScrollCaptureConnection());
- }
- callbacks.onConnected(
- mScrollCaptureConnection,
- selectedTarget.getScrollBounds(),
- selectedTarget.getPositionInWindow());
+ callbacks.onScrollCaptureResponse(response.build());
} catch (RemoteException e) {
if (DEBUG_SCROLL_CAPTURE) {
- Log.w(TAG, "Failed to send scroll capture search result.", e);
+ Log.w(TAG, "Failed to send scroll capture search response.", e);
}
- mScrollCaptureConnection.disconnect();
- mScrollCaptureConnection = null;
+ connection.close();
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 4ecdd78..cf5ec8d 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1716,13 +1716,22 @@
* For the blur region to be visible, the window has to be translucent. See
* {@link android.R.styleable#Window_windowIsTranslucent}.
*
- * Note the difference with {@link android.view.WindowManager.LayoutParams#blurBehindRadius},
+ * Note the difference with {@link WindowManager.LayoutParams#setBlurBehindRadius},
* which blurs the whole screen behind the window. Background blur blurs the screen behind
* only within the bounds of the window.
*
+ * Some devices might not support cross-window blur due to GPU limitations. It can also be
+ * disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+ * when minimal post processing is requested. In such situations, no blur will be computed or
+ * drawn, resulting in a transparent window background. To avoid this, the app might want to
+ * change its theme to one that does not use blurs. To listen for cross-window blur
+ * enabled/disabled events, use {@link WindowManager#addCrossWindowBlurEnabledListener}.
+ *
* @param blurRadius The blur radius to use for window background blur in pixels
*
* @see android.R.styleable#Window_windowBackgroundBlurRadius
+ * @see WindowManager.LayoutParams#setBlurBehindRadius
+ * @see WindowManager#addCrossWindowBlurEnabledListener
*/
public void setBackgroundBlurRadius(int blurRadius) {}
@@ -2621,7 +2630,6 @@
* callback with the root view of the window.
*
* @param callback the callback to add
- * @hide
*/
public void registerScrollCaptureCallback(@NonNull ScrollCaptureCallback callback) {
}
@@ -2630,7 +2638,6 @@
* Unregisters a {@link ScrollCaptureCallback} previously registered with this window.
*
* @param callback the callback to remove
- * @hide
*/
public void unregisterScrollCaptureCallback(@NonNull ScrollCaptureCallback callback) {
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 9e87c95..2053826 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -82,6 +82,7 @@
import android.Manifest.permission;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -120,6 +121,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.function.Consumer;
/**
* The interface that apps use to talk to the window manager.
@@ -808,6 +810,64 @@
return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
}
+ /**
+ * Returns whether cross-window blur is currently enabled. This affects both window blur behind
+ * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur (see
+ * {@link Window#setBackgroundBlurRadius}).
+ *
+ * Cross-window blur might not be supported by some devices due to GPU limitations. It can also
+ * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+ * when minimal post processing is requested. In such situations, no blur will be computed or
+ * drawn, so the blur target area will not be blurred. To handle this, the app might want to
+ * change its theme to one that does not use blurs. To listen for cross-window blur
+ * enabled/disabled events, use {@link #addCrossWindowBlurEnabledListener}.
+ *
+ * @see #addCrossWindowBlurEnabledListener
+ * @see LayoutParams#setBlurBehindRadius
+ * @see Window#setBackgroundBlurRadius
+ */
+ default boolean isCrossWindowBlurEnabled() {
+ return false;
+ }
+
+ /**
+ * Adds a listener, which will be called when cross-window blurs are enabled/disabled at
+ * runtime. This affects both window blur behind (see {@link LayoutParams#setBlurBehindRadius})
+ * and window background blur (see {@link Window#setBackgroundBlurRadius}).
+ *
+ * Cross-window blur might not be supported by some devices due to GPU limitations. It can also
+ * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+ * when minimal post processing is requested. In such situations, no blur will be computed or
+ * drawn, so the blur target area will not be blurred. To handle this, the app might want to
+ * change its theme to one that does not use blurs.
+ *
+ * The listener will be called on the main thread.
+ *
+ * If the listener is added successfully, it will be called immediately with the current
+ * cross-window blur enabled state.
+ *
+ *
+ * @param listener the listener to be added. It will be called back with a boolean parameter,
+ * which is true if cross-window blur is enabled and false if it is disabled
+ *
+ * @see #removeCrossWindowBlurEnabledListener
+ * @see #isCrossWindowBlurEnabled
+ * @see LayoutParams#setBlurBehindRadius
+ * @see Window#setBackgroundBlurRadius
+ */
+ default void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+ }
+
+ /**
+ * Removes a listener, previously added with {@link #addCrossWindowBlurEnabledListener}
+ *
+ * @param listener the listener to be removed
+ *
+ * @see #addCrossWindowBlurEnabledListener
+ */
+ default void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+ }
+
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
@@ -3238,9 +3298,9 @@
* The blur behind radius range starts at 0, which means no blur, and increases until 150
* for the densest blur.
*
- * @see #FLAG_BLUR_BEHIND
+ * @see #setBlurBehindRadius
*/
- public int blurBehindRadius = 0;
+ private int mBlurBehindRadius = 0;
/**
* The color mode requested by this window. The target display may
@@ -3534,6 +3594,50 @@
return mColorMode;
}
+ /**
+ * Blurs the screen behind the window. The effect is similar to that of {@link #dimAmount},
+ * but instead of dimmed, the content behind the window will be blurred (or combined with
+ * the dim amount, if such is specified).
+ *
+ * The density of the blur is set by the blur radius. The radius defines the size
+ * of the neighbouring area, from which pixels will be averaged to form the final
+ * color for each pixel. The operation approximates a Gaussian blur.
+ * A radius of 0 means no blur. The higher the radius, the denser the blur.
+ *
+ * Note the difference with {@link android.view.Window#setBackgroundBlurRadius},
+ * which blurs only within the bounds of the window. Blur behind blurs the whole screen
+ * behind the window.
+ *
+ * Requires {@link #FLAG_BLUR_BEHIND} to be set.
+ *
+ * Cross-window blur might not be supported by some devices due to GPU limitations. It can
+ * also be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling
+ * is used or when minimal post processing is requested. In such situations, no blur will
+ * be computed or drawn, resulting in there being no depth separation between the window
+ * and the content behind it. To avoid this, the app might want to use more
+ * {@link #dimAmount} on its window. To listen for cross-window blur enabled/disabled
+ * events, use {@link #addCrossWindowBlurEnabledListener}.
+ *
+ * @param blurBehindRadius The blur radius to use for blur behind in pixels
+ *
+ * @see #FLAG_BLUR_BEHIND
+ * @see #getBlurBehindRadius
+ * @see WindowManager#addCrossWindowBlurEnabledListener
+ * @see Window#setBackgroundBlurRadius
+ */
+ public void setBlurBehindRadius(@IntRange(from = 0) int blurBehindRadius) {
+ mBlurBehindRadius = blurBehindRadius;
+ }
+
+ /**
+ * Returns the blur behind radius of the window.
+ *
+ * @see #setBlurBehindRadius
+ */
+ public int getBlurBehindRadius() {
+ return mBlurBehindRadius;
+ }
+
/** @hide */
@SystemApi
public final void setUserActivityTimeout(long timeout) {
@@ -3629,7 +3733,7 @@
out.writeInt(mFitInsetsSides);
out.writeBoolean(mFitInsetsIgnoringVisibility);
out.writeBoolean(preferMinimalPostProcessing);
- out.writeInt(blurBehindRadius);
+ out.writeInt(mBlurBehindRadius);
if (providesInsetsTypes != null) {
out.writeInt(providesInsetsTypes.length);
out.writeIntArray(providesInsetsTypes);
@@ -3698,7 +3802,7 @@
mFitInsetsSides = in.readInt();
mFitInsetsIgnoringVisibility = in.readBoolean();
preferMinimalPostProcessing = in.readBoolean();
- blurBehindRadius = in.readInt();
+ mBlurBehindRadius = in.readInt();
int insetsTypesLength = in.readInt();
if (insetsTypesLength > 0) {
providesInsetsTypes = new int[insetsTypesLength];
@@ -3752,7 +3856,7 @@
/** {@hide} */
public static final int MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED = 1 << 28;
/** {@hide} */
- public static final int BACKGROUND_BLUR_RADIUS_CHANGED = 1 << 29;
+ public static final int BLUR_BEHIND_RADIUS_CHANGED = 1 << 29;
// internal buffer to backup/restore parameters under compatibility mode.
private int[] mCompatibilityParamsBackup = null;
@@ -3943,9 +4047,9 @@
changes |= MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED;
}
- if (blurBehindRadius != o.blurBehindRadius) {
- blurBehindRadius = o.blurBehindRadius;
- changes |= BACKGROUND_BLUR_RADIUS_CHANGED;
+ if (mBlurBehindRadius != o.mBlurBehindRadius) {
+ mBlurBehindRadius = o.mBlurBehindRadius;
+ changes |= BLUR_BEHIND_RADIUS_CHANGED;
}
// This can't change, it's only set at window creation time.
@@ -4111,9 +4215,9 @@
sb.append(" preferMinimalPostProcessing=");
sb.append(preferMinimalPostProcessing);
}
- if (blurBehindRadius != 0) {
+ if (mBlurBehindRadius != 0) {
sb.append(" blurBehindRadius=");
- sb.append(blurBehindRadius);
+ sb.append(mBlurBehindRadius);
}
sb.append(System.lineSeparator());
sb.append(prefix).append(" fl=").append(
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 23842b3..b398707 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -40,6 +40,7 @@
import com.android.internal.os.IResultReceiver;
import java.util.List;
+import java.util.function.Consumer;
/**
* Provides low-level communication with the system window manager for
@@ -301,4 +302,19 @@
throw e.rethrowFromSystemServer();
}
}
+
+ @Override
+ public boolean isCrossWindowBlurEnabled() {
+ return CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled();
+ }
+
+ @Override
+ public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+ CrossWindowBlurListeners.getInstance().addListener(listener);
+ }
+
+ @Override
+ public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+ CrossWindowBlurListeners.getInstance().removeListener(listener);
+ }
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 9bf3626..9998fbc 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.TaskInfo;
+import android.app.assist.ActivityId;
import android.content.ComponentName;
import android.content.Context;
import android.content.LocusId;
@@ -36,6 +37,8 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
/**
* Context associated with a {@link ContentCaptureSession} - see {@link ContentCaptureManager} for
* more info.
@@ -99,16 +102,17 @@
// Fields below are set by server when the session starts
private final @Nullable ComponentName mComponentName;
- private final int mTaskId;
private final int mFlags;
private final int mDisplayId;
+ private final ActivityId mActivityId;
// Fields below are set by the service upon "delivery" and are not marshalled in the parcel
private int mParentSessionId = NO_SESSION_ID;
/** @hide */
public ContentCaptureContext(@Nullable ContentCaptureContext clientContext,
- @NonNull ComponentName componentName, int taskId, int displayId, int flags) {
+ @NonNull ActivityId activityId, @NonNull ComponentName componentName, int displayId,
+ int flags) {
if (clientContext != null) {
mHasClientContext = true;
mExtras = clientContext.mExtras;
@@ -118,10 +122,10 @@
mExtras = null;
mId = null;
}
- mComponentName = Preconditions.checkNotNull(componentName);
- mTaskId = taskId;
- mDisplayId = displayId;
+ mComponentName = Objects.requireNonNull(componentName);
mFlags = flags;
+ mDisplayId = displayId;
+ mActivityId = activityId;
}
private ContentCaptureContext(@NonNull Builder builder) {
@@ -130,8 +134,9 @@
mId = builder.mId;
mComponentName = null;
- mTaskId = mFlags = 0;
+ mFlags = 0;
mDisplayId = Display.INVALID_DISPLAY;
+ mActivityId = null;
}
/** @hide */
@@ -140,9 +145,9 @@
mExtras = original.mExtras;
mId = original.mId;
mComponentName = original.mComponentName;
- mTaskId = original.mTaskId;
mFlags = original.mFlags | extraFlags;
mDisplayId = original.mDisplayId;
+ mActivityId = original.mActivityId;
}
/**
@@ -170,7 +175,7 @@
*/
@SystemApi
public int getTaskId() {
- return mTaskId;
+ return mHasClientContext ? 0 : mActivityId.getTaskId();
}
/**
@@ -184,6 +189,18 @@
}
/**
+ * Gets the Activity id information associated with this context, or {@code null} when it is a
+ * child session.
+ *
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public ActivityId getActivityId() {
+ return mHasClientContext ? null : mActivityId;
+ }
+
+ /**
* Gets the id of the session that originated this session (through
* {@link ContentCaptureSession#createContentCaptureSession(ContentCaptureContext)}),
* or {@code null} if this is the main session associated with the Activity's {@link Context}.
@@ -309,7 +326,7 @@
if (mId != null) {
pw.print(", id="); mId.dump(pw);
}
- pw.print(", taskId="); pw.print(mTaskId);
+ pw.print(", activityId="); pw.print(mActivityId);
pw.print(", displayId="); pw.print(mDisplayId);
if (mParentSessionId != NO_SESSION_ID) {
pw.print(", parentId="); pw.print(mParentSessionId);
@@ -333,7 +350,7 @@
if (fromServer()) {
builder.append("act=").append(ComponentName.flattenToShortString(mComponentName))
- .append(", taskId=").append(mTaskId)
+ .append(", activityId=").append(mActivityId)
.append(", displayId=").append(mDisplayId)
.append(", flags=").append(mFlags);
} else {
@@ -363,9 +380,9 @@
}
parcel.writeParcelable(mComponentName, flags);
if (fromServer()) {
- parcel.writeInt(mTaskId);
parcel.writeInt(mDisplayId);
parcel.writeInt(mFlags);
+ mActivityId.writeToParcel(parcel, flags);
}
}
@@ -393,11 +410,12 @@
// Client-state only
return clientContext;
} else {
- final int taskId = parcel.readInt();
final int displayId = parcel.readInt();
final int flags = parcel.readInt();
- return new ContentCaptureContext(clientContext, componentName, taskId, displayId,
- flags);
+ final ActivityId activityId = new ActivityId(parcel);
+
+ return new ContentCaptureContext(clientContext, activityId, componentName,
+ displayId, flags);
}
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 10f6c61..9523bcd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -23,10 +23,13 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UiThread;
+import android.annotation.UserIdInt;
+import android.app.Service;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Context;
@@ -432,10 +435,11 @@
/** @hide */
@UiThread
public void onActivityCreated(@NonNull IBinder applicationToken,
- @NonNull ComponentName activityComponent) {
+ @NonNull IBinder shareableActivityToken, @NonNull ComponentName activityComponent) {
if (mOptions.lite) return;
synchronized (mLock) {
- getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
+ getMainContentCaptureSession().start(applicationToken, shareableActivityToken,
+ activityComponent, mFlags);
}
}
@@ -755,6 +759,74 @@
}
}
+ /**
+ * Resets the temporary content capture service implementation to the default component.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+ public static void resetTemporaryService(@UserIdInt int userId) {
+ final IContentCaptureManager service = getService();
+ if (service == null) {
+ Log.e(TAG, "IContentCaptureManager is null");
+ }
+ try {
+ service.resetTemporaryService(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Temporarily sets the content capture service implementation.
+ *
+ * @param userId user Id to set the temporary service on.
+ * @param serviceName name of the new component
+ * @param duration how long the change will be valid (the service will be automatically reset
+ * to the default component after this timeout expires).
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+ public static void setTemporaryService(
+ @UserIdInt int userId, @NonNull String serviceName, int duration) {
+ final IContentCaptureManager service = getService();
+ if (service == null) {
+ Log.e(TAG, "IContentCaptureManager is null");
+ }
+ try {
+ service.setTemporaryService(userId, serviceName, duration);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets whether the default content capture service should be used.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+ public static void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+ final IContentCaptureManager service = getService();
+ if (service == null) {
+ Log.e(TAG, "IContentCaptureManager is null");
+ }
+ try {
+ service.setDefaultServiceEnabled(userId, enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static IContentCaptureManager getService() {
+ return IContentCaptureManager.Stub.asInterface(ServiceManager.getService(
+ Service.CONTENT_CAPTURE_MANAGER_SERVICE));
+ }
+
private interface MyRunnable {
void run(@NonNull SyncResultReceiver receiver) throws RemoteException;
}
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 01ead46..b1b443f 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -44,8 +44,9 @@
* @param flags Meta flags that enable or disable content capture (see
* {@link IContentCaptureContext#flags}).
*/
- void startSession(IBinder activityToken, in ComponentName componentName,
- int sessionId, int flags, in IResultReceiver result);
+ void startSession(IBinder activityToken, IBinder shareableActivityToken,
+ in ComponentName componentName, int sessionId, int flags,
+ in IResultReceiver result);
/**
* Marks the end of a session for the calling user identified by
@@ -85,4 +86,19 @@
* Returns a list with the ContentCaptureConditions for the package (or null if not defined).
*/
void getContentCaptureConditions(String packageName, in IResultReceiver result);
+
+ /**
+ * Resets the temporary service implementation to the default component.
+ */
+ void resetTemporaryService(int userId);
+
+ /**
+ * Temporarily sets the service implementation.
+ */
+ void setTemporaryService(int userId, in String serviceName, int duration);
+
+ /**
+ * Sets whether the default service should be used.
+ */
+ void setDefaultServiceEnabled(int userId, boolean enabled);
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 3c18b6b..5ca793e 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -123,6 +123,8 @@
@Nullable
private IBinder mApplicationToken;
+ @Nullable
+ private IBinder mShareableActivityToken;
@Nullable
private ComponentName mComponentName;
@@ -217,8 +219,8 @@
* Starts this session.
*/
@UiThread
- void start(@NonNull IBinder token, @NonNull ComponentName component,
- int flags) {
+ void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
+ @NonNull ComponentName component, int flags) {
if (!isContentCaptureEnabled()) return;
if (sVerbose) {
@@ -237,6 +239,7 @@
}
mState = STATE_WAITING_FOR_SERVER;
mApplicationToken = token;
+ mShareableActivityToken = shareableActivityToken;
mComponentName = component;
if (sVerbose) {
@@ -245,8 +248,8 @@
}
try {
- mSystemServerInterface.startSession(mApplicationToken, component, mId, flags,
- mSessionStateReceiver);
+ mSystemServerInterface.startSession(mApplicationToken, mShareableActivityToken,
+ component, mId, flags, mSessionStateReceiver);
} catch (RemoteException e) {
Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
}
@@ -583,6 +586,7 @@
mDisabled.set((newState & STATE_DISABLED) != 0);
// TODO(b/122454205): must reset children (which currently is owned by superclass)
mApplicationToken = null;
+ mShareableActivityToken = null;
mComponentName = null;
mEvents = null;
if (mDirectServiceInterface != null) {
@@ -721,6 +725,10 @@
if (mApplicationToken != null) {
pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
}
+ if (mShareableActivityToken != null) {
+ pw.print(prefix); pw.print("sharable activity token: ");
+ pw.println(mShareableActivityToken);
+ }
if (mComponentName != null) {
pw.print(prefix); pw.print("component name: ");
pw.println(mComponentName.flattenToShortString());
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 6ade5e6..de4554b 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -105,7 +105,7 @@
*/
@MainThread
default void initializeInternal(IBinder token, int displayId,
- IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
+ IInputMethodPrivilegedOperations privilegedOperations) {
updateInputMethodDisplay(displayId);
attachToken(token);
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 25712f8..5d876a6 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -18,23 +18,19 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
-import android.inputmethodservice.InputMethodService;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -64,7 +60,6 @@
* @attr ref android.R.styleable#InputMethod_isDefault
* @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
* @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
- * @attr ref android.R.styleable#InputMethod_configChanges
*/
public final class InputMethodInfo implements Parcelable {
static final String TAG = "InputMethodInfo";
@@ -123,12 +118,6 @@
private final boolean mInlineSuggestionsEnabled;
/**
- * The flag for configurations IME assumes the responsibility for handling in
- * {@link InputMethodService#onConfigurationChanged(Configuration)}}.
- */
- private final int mHandledConfigChanges;
-
- /**
* @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
* @return a unique ID to be returned by {@link #getId()}. We have used
* {@link ComponentName#flattenToShortString()} for this purpose (and it is already
@@ -214,8 +203,6 @@
false);
inlineSuggestionsEnabled = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
- mHandledConfigChanges = sa.getInt(
- com.android.internal.R.styleable.InputMethod_configChanges, 0);
sa.recycle();
final int depth = parser.getDepth();
@@ -300,7 +287,6 @@
mIsVrOnly = source.readBoolean();
mService = ResolveInfo.CREATOR.createFromParcel(source);
mSubtypes = new InputMethodSubtypeArray(source);
- mHandledConfigChanges = source.readInt();
mForceDefault = false;
}
@@ -312,22 +298,7 @@
this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
- false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
- 0 /* handledConfigChanges */);
- }
-
- /**
- * Temporary API for creating a built-in input method for test.
- * @hide
- */
- @TestApi
- public InputMethodInfo(@NonNull String packageName, @NonNull String className,
- @NonNull CharSequence label, @NonNull String settingsActivity,
- int handledConfigChanges) {
- this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
- settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
- false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
- false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges);
+ false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
}
/**
@@ -339,7 +310,7 @@
boolean forceDefault) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
- false /* isVrOnly */, 0 /* handledconfigChanges */);
+ false /* isVrOnly */);
}
/**
@@ -350,8 +321,7 @@
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
- supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
- 0 /* handledConfigChanges */);
+ supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
}
/**
@@ -361,7 +331,7 @@
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
- boolean isVrOnly, int handledConfigChanges) {
+ boolean isVrOnly) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -373,7 +343,6 @@
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
mIsVrOnly = isVrOnly;
- mHandledConfigChanges = handledConfigChanges;
}
private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
@@ -520,17 +489,6 @@
}
}
- /**
- * Returns the bit mask of kinds of configuration changes that this IME
- * can handle itself (without being restarted by the system).
- *
- * @attr ref android.R.styleable#InputMethod_configChanges
- */
- @ActivityInfo.Config
- public int getConfigChanges() {
- return mHandledConfigChanges;
- }
-
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
@@ -621,7 +579,6 @@
dest.writeBoolean(mIsVrOnly);
mService.writeToParcel(dest, flags);
mSubtypes.writeToParcel(dest);
- dest.writeInt(mHandledConfigChanges);
}
/**
diff --git a/core/java/android/view/translation/TranslationSpec.java b/core/java/android/view/translation/TranslationSpec.java
index ab1bc47..16418a7 100644
--- a/core/java/android/view/translation/TranslationSpec.java
+++ b/core/java/android/view/translation/TranslationSpec.java
@@ -28,7 +28,7 @@
* <p>This spec help specify information such as the language/locale for the translation, as well
* as the data format for the translation (text, audio, etc.)</p>
*/
-@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true)
+@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true, genToString = true)
public final class TranslationSpec implements Parcelable {
/** Data format for translation is text. */
@@ -99,6 +99,18 @@
@Override
@DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "TranslationSpec { " +
+ "language = " + mLanguage + ", " +
+ "dataFormat = " + mDataFormat +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
public boolean equals(@android.annotation.Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
// boolean fieldNameEquals(TranslationSpec other) { ... }
@@ -175,10 +187,10 @@
};
@DataClass.Generated(
- time = 1609964630624L,
+ time = 1614326090637L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationSpec.java",
- inputSignatures = "public static final int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index 22c3e57..163f832 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -35,6 +35,7 @@
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.SyncResultReceiver;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -221,6 +222,12 @@
return mId;
}
+ /** @hide */
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ pw.print(prefix); pw.print("sourceSpec: "); pw.println(mSourceSpec);
+ pw.print(prefix); pw.print("destSpec: "); pw.println(mDestSpec);
+ }
+
/**
* Requests a translation for the provided {@link TranslationRequest} using the Translator's
* source spec and destination spec.
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index b49d3c0..8100612 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -32,11 +32,15 @@
import android.util.Log;
import android.util.Pair;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
import android.view.autofill.AutofillId;
import android.view.translation.UiTranslationManager.UiTranslationState;
import com.android.internal.util.function.pooled.PooledLambda;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -130,6 +134,23 @@
}
/**
+ * Called to dump the translation information for Activity.
+ */
+ public void dump(String outerPrefix, PrintWriter pw) {
+ pw.print(outerPrefix); pw.println("UiTranslationController:");
+ final String pfx = outerPrefix + " ";
+ pw.print(pfx); pw.print("activity: "); pw.println(mActivity);
+ final int translatorSize = mTranslators.size();
+ pw.print(outerPrefix); pw.print("number translator: "); pw.println(translatorSize);
+ for (int i = 0; i < translatorSize; i++) {
+ pw.print(outerPrefix); pw.print("#"); pw.println(i);
+ final Translator translator = mTranslators.valueAt(i);
+ translator.dump(outerPrefix, pw);
+ pw.println();
+ }
+ }
+
+ /**
* The method is used by {@link Translator}, it will be called when the translation is done. The
* translation result can be get from here.
*/
@@ -194,24 +215,19 @@
private void onUiTranslationStarted(Translator translator, List<AutofillId> views) {
synchronized (mLock) {
// Find Views collect the translation data
- // TODO(b/178084101): try to optimize, e.g. to this in a single traversal
- final int viewCounts = views.size();
final ArrayList<TranslationRequest> requests = new ArrayList<>();
- for (int i = 0; i < viewCounts; i++) {
- final AutofillId viewAutofillId = views.get(i);
- final View view = mActivity.findViewByAutofillIdTraversal(viewAutofillId);
- if (view == null) {
- Log.w(TAG, "Can not find the View for autofill id= " + viewAutofillId);
- continue;
- }
- mViews.put(viewAutofillId, new WeakReference<>(view));
+ final ArrayList<View> foundViews = new ArrayList<>();
+ findViewsTraversalByAutofillIds(views, foundViews);
+ for (int i = 0; i < foundViews.size(); i++) {
+ final View view = foundViews.get(i);
+ final int currentCount = i;
mActivity.runOnUiThread(() -> {
final TranslationRequest translationRequest = view.onCreateTranslationRequest();
if (translationRequest != null
&& translationRequest.getTranslationText().length() > 0) {
requests.add(translationRequest);
}
- if (requests.size() == viewCounts) {
+ if (currentCount == (foundViews.size() - 1)) {
Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request.");
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
UiTranslationController::sendTranslationRequest,
@@ -222,6 +238,42 @@
}
}
+ private void findViewsTraversalByAutofillIds(List<AutofillId> sourceViewIds,
+ ArrayList<View> foundViews) {
+ final ArrayList<ViewRootImpl> roots =
+ WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
+ for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+ final View rootView = roots.get(rootNum).getView();
+ if (rootView instanceof ViewGroup) {
+ findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds, foundViews);
+ } else {
+ addViewIfNeeded(sourceViewIds, rootView, foundViews);
+ }
+ }
+ }
+
+ private void findViewsTraversalByAutofillIds(ViewGroup viewGroup,
+ List<AutofillId> sourceViewIds, ArrayList<View> foundViews) {
+ final int childCount = viewGroup.getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ final View child = viewGroup.getChildAt(i);
+ if (child instanceof ViewGroup) {
+ findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds, foundViews);
+ } else {
+ addViewIfNeeded(sourceViewIds, child, foundViews);
+ }
+ }
+ }
+
+ private void addViewIfNeeded(List<AutofillId> sourceViewIds, View view,
+ ArrayList<View> foundViews) {
+ final AutofillId autofillId = view.getAutofillId();
+ if (sourceViewIds.contains(autofillId)) {
+ mViews.put(autofillId, new WeakReference<>(view));
+ foundViews.add(view);
+ }
+ }
+
private void runForEachView(Consumer<View> action) {
synchronized (mLock) {
final ArrayMap<AutofillId, WeakReference<View>> views = new ArrayMap<>(mViews);
diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java
index e22a5eb..acf9882 100644
--- a/core/java/android/window/ClientWindowFrames.java
+++ b/core/java/android/window/ClientWindowFrames.java
@@ -58,9 +58,9 @@
/** Needed for AIDL out parameters. */
public void readFromParcel(Parcel in) {
- frame.set(Rect.CREATOR.createFromParcel(in));
- displayFrame.set(Rect.CREATOR.createFromParcel(in));
- backdropFrame.set(Rect.CREATOR.createFromParcel(in));
+ frame.readFromParcel(in);
+ displayFrame.readFromParcel(in);
+ backdropFrame.readFromParcel(in);
}
@Override
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index 63b9e9b..d1c1e40 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -35,6 +35,31 @@
@TestApi
public final class StartingWindowInfo implements Parcelable {
/**
+ * Prefer nothing or not care the type of starting window.
+ * @hide
+ */
+ public static final int STARTING_WINDOW_TYPE_NONE = 0;
+ /**
+ * Prefer splash screen starting window.
+ * @hide
+ */
+ public static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 1;
+ /**
+ * Prefer snapshot starting window.
+ * @hide
+ */
+ public static final int STARTING_WINDOW_TYPE_SNAPSHOT = 2;
+ /**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "STARTING_WINDOW_TYPE_", value = {
+ STARTING_WINDOW_TYPE_NONE,
+ STARTING_WINDOW_TYPE_SPLASH_SCREEN,
+ STARTING_WINDOW_TYPE_SNAPSHOT
+ })
+ public @interface StartingWindowType {}
+
+ /**
* The {@link TaskInfo} from this task.
* @hide
*/
diff --git a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
index 96dac56..402d7fe 100644
--- a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
+++ b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
@@ -19,6 +19,7 @@
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UiThread;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -31,12 +32,14 @@
import android.graphics.Rect;
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
-import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
-import android.view.SurfaceControl;
+import android.util.LongSparseArray;
import android.view.ViewRootImpl;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
/**
* A drawable that keeps track of a blur region, pokes a hole under it, and propagates its state
@@ -52,26 +55,40 @@
private final Paint mPaint = new Paint();
private final Path mRectPath = new Path();
private final float[] mTmpRadii = new float[8];
- private final SurfaceControl.BlurRegion mBlurRegion = new SurfaceControl.BlurRegion();
- // This will be called from a thread pool.
- private final RenderNode.PositionUpdateListener mPositionUpdateListener =
+ private boolean mVisible = true;
+
+ // Confined to UiThread. The values are copied into a BlurRegion, which lives on
+ // RenderThread to avoid interference with UiThread updates.
+ private int mBlurRadius;
+ private float mCornerRadiusTL;
+ private float mCornerRadiusTR;
+ private float mCornerRadiusBL;
+ private float mCornerRadiusBR;
+ private float mAlpha = 1;
+
+ // Do not update from UiThread. This holds the latest position for this drawable. It is used
+ // by the Aggregator from RenderThread to get the final position of the blur region sent to SF
+ private final Rect mRect = new Rect();
+ // This is called from a thread pool. The callbacks might come out of order w.r.t. the frame
+ // number, so we send a Runnable holding the actual update to the Aggregator. The Aggregator
+ // can apply the update on RenderThread when processing that same frame.
+ @VisibleForTesting
+ public final RenderNode.PositionUpdateListener mPositionUpdateListener =
new RenderNode.PositionUpdateListener() {
@Override
public void positionChanged(long frameNumber, int left, int top, int right,
int bottom) {
- synchronized (mAggregator) {
- mBlurRegion.rect.set(left, top, right, bottom);
- mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
- }
+ mAggregator.onRenderNodePositionChanged(frameNumber, () -> {
+ mRect.set(left, top, right, bottom);
+ });
}
@Override
public void positionLost(long frameNumber) {
- synchronized (mAggregator) {
- mBlurRegion.rect.setEmpty();
- mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
- }
+ mAggregator.onRenderNodePositionChanged(frameNumber, () -> {
+ mRect.setEmpty();
+ });
}
};
@@ -79,6 +96,7 @@
mAggregator = aggregator;
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
mPaint.setColor(Color.TRANSPARENT);
+ mPaint.setAntiAlias(true);
mRenderNode = new RenderNode("BackgroundBlurDrawable");
mRenderNode.addPositionUpdateListener(mPositionUpdateListener);
}
@@ -104,23 +122,30 @@
public boolean setVisible(boolean visible, boolean restart) {
boolean changed = super.setVisible(visible, restart);
if (changed) {
- mBlurRegion.visible = visible;
+ mVisible = visible;
+ mAggregator.onBlurDrawableUpdated(this);
}
return changed;
}
@Override
public void setAlpha(int alpha) {
- mBlurRegion.alpha = alpha / 255f;
- invalidateSelf();
+ if (mAlpha != alpha / 255f) {
+ mAlpha = alpha / 255f;
+ invalidateSelf();
+ mAggregator.onBlurDrawableUpdated(this);
+ }
}
/**
* Blur radius in pixels.
*/
public void setBlurRadius(int blurRadius) {
- mBlurRegion.blurRadius = blurRadius;
- invalidateSelf();
+ if (mBlurRadius != blurRadius) {
+ mBlurRadius = blurRadius;
+ invalidateSelf();
+ mAggregator.onBlurDrawableUpdated(this);
+ }
}
/**
@@ -139,14 +164,18 @@
*/
public void setCornerRadius(float cornerRadiusTL, float cornerRadiusTR, float cornerRadiusBL,
float cornerRadiusBR) {
- synchronized (mAggregator) {
- mBlurRegion.cornerRadiusTL = cornerRadiusTL;
- mBlurRegion.cornerRadiusTR = cornerRadiusTR;
- mBlurRegion.cornerRadiusBL = cornerRadiusBL;
- mBlurRegion.cornerRadiusBR = cornerRadiusBR;
+ if (mCornerRadiusTL != cornerRadiusTL
+ || mCornerRadiusTR != cornerRadiusTR
+ || mCornerRadiusBL != cornerRadiusBL
+ || mCornerRadiusBR != cornerRadiusBR) {
+ mCornerRadiusTL = cornerRadiusTL;
+ mCornerRadiusTR = cornerRadiusTR;
+ mCornerRadiusBL = cornerRadiusBL;
+ mCornerRadiusBR = cornerRadiusBR;
+ updatePath();
+ invalidateSelf();
+ mAggregator.onBlurDrawableUpdated(this);
}
- updatePath();
- invalidateSelf();
}
@Override
@@ -157,12 +186,10 @@
}
private void updatePath() {
- synchronized (mAggregator) {
- mTmpRadii[0] = mTmpRadii[1] = mBlurRegion.cornerRadiusTL;
- mTmpRadii[2] = mTmpRadii[3] = mBlurRegion.cornerRadiusTR;
- mTmpRadii[4] = mTmpRadii[5] = mBlurRegion.cornerRadiusBL;
- mTmpRadii[6] = mTmpRadii[7] = mBlurRegion.cornerRadiusBR;
- }
+ mTmpRadii[0] = mTmpRadii[1] = mCornerRadiusTL;
+ mTmpRadii[2] = mTmpRadii[3] = mCornerRadiusTR;
+ mTmpRadii[4] = mTmpRadii[5] = mCornerRadiusBL;
+ mTmpRadii[6] = mTmpRadii[7] = mCornerRadiusBR;
mRectPath.reset();
if (getAlpha() == 0 || !isVisible()) {
return;
@@ -182,17 +209,32 @@
return PixelFormat.TRANSLUCENT;
}
+ @Override
+ public String toString() {
+ return "BackgroundBlurDrawable{"
+ + "blurRadius=" + mBlurRadius
+ + ", corners={" + mCornerRadiusTL
+ + "," + mCornerRadiusTR
+ + "," + mCornerRadiusBL
+ + "," + mCornerRadiusBR
+ + "}, alpha=" + mAlpha
+ + ", visible=" + mVisible
+ + "}";
+ }
+
/**
* Responsible for keeping track of all blur regions of a {@link ViewRootImpl} and posting a
* message when it's time to propagate them.
*/
public static final class Aggregator {
-
- private final ArrayMap<BackgroundBlurDrawable, SurfaceControl.BlurRegion> mBlurRegions =
- new ArrayMap<>();
+ private final Object mRtLock = new Object();
+ // Maintains a list of all *visible* blur drawables. Confined to UI thread
+ private final ArraySet<BackgroundBlurDrawable> mDrawables = new ArraySet();
+ @GuardedBy("mRtLock")
+ private final LongSparseArray<ArraySet<Runnable>> mFrameRtUpdates = new LongSparseArray();
private final ViewRootImpl mViewRoot;
- private float[][] mTmpBlurRegionsArray;
- private boolean mNeedsUpdate;
+ private BlurRegion[] mTmpBlurRegionsForFrame = new BlurRegion[0];
+ private boolean mHasUiUpdates;
public Aggregator(ViewRootImpl viewRoot) {
mViewRoot = viewRoot;
@@ -209,60 +251,191 @@
}
/**
- * Called from RenderThread only, already locked.
- * @param drawable
- * @param blurRegion
+ * Called when a BackgroundBlurDrawable has been updated
*/
- void onBlurRegionUpdated(BackgroundBlurDrawable drawable,
- SurfaceControl.BlurRegion blurRegion) {
- if (blurRegion.rect.isEmpty() || blurRegion.alpha == 0 || blurRegion.blurRadius == 0
- || !blurRegion.visible) {
- mBlurRegions.remove(drawable);
- mNeedsUpdate = true;
- if (DEBUG) {
- Log.d(TAG, "Remove " + blurRegion);
+ @UiThread
+ void onBlurDrawableUpdated(BackgroundBlurDrawable drawable) {
+ final boolean shouldBeDrawn =
+ drawable.mAlpha != 0 && drawable.mBlurRadius > 0 && drawable.mVisible;
+ final boolean isDrawn = mDrawables.contains(drawable);
+ if (shouldBeDrawn) {
+ mHasUiUpdates = true;
+ if (!isDrawn) {
+ mDrawables.add(drawable);
+ if (DEBUG) {
+ Log.d(TAG, "Add " + drawable);
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Update " + drawable);
+ }
}
- } else {
- mBlurRegions.put(drawable, blurRegion);
- mNeedsUpdate = true;
+ } else if (!shouldBeDrawn && isDrawn) {
+ mHasUiUpdates = true;
+ mDrawables.remove(drawable);
if (DEBUG) {
- Log.d(TAG, "Update " + blurRegion);
+ Log.d(TAG, "Remove " + drawable);
}
}
}
+ // Called from a thread pool
+ void onRenderNodePositionChanged(long frameNumber, Runnable update) {
+ // One of the blur region's position has changed, so we have to send an updated list
+ // of blur regions to SurfaceFlinger for this frame.
+ synchronized (mRtLock) {
+ ArraySet<Runnable> frameRtUpdates = mFrameRtUpdates.get(frameNumber);
+ if (frameRtUpdates == null) {
+ frameRtUpdates = new ArraySet<>();
+ mFrameRtUpdates.put(frameNumber, frameRtUpdates);
+ }
+ frameRtUpdates.add(update);
+ }
+ }
+
/**
- * If there are any blur regions visible on the screen at the moment.
+ * @return true if there are any updates that need to be sent to SF
*/
+ @UiThread
+ public boolean hasUpdates() {
+ return mHasUiUpdates;
+ }
+
+ /**
+ * @return true if there are any visible blur regions
+ */
+ @UiThread
public boolean hasRegions() {
- return mBlurRegions.size() > 0;
+ return mDrawables.size() > 0;
}
/**
- * Dispatch blur updates, if there were any.
- * @param frameNumber Frame where the update should happen.
+ * @return an array of BlurRegions, which are holding a copy of the information in
+ * all the currently visible BackgroundBlurDrawables
*/
- public void dispatchBlurTransactionIfNeeded(long frameNumber) {
- synchronized (this) {
- if (!mNeedsUpdate) {
- return;
+ @UiThread
+ public BlurRegion[] getBlurRegionsCopyForRT() {
+ if (mHasUiUpdates) {
+ mTmpBlurRegionsForFrame = new BlurRegion[mDrawables.size()];
+ for (int i = 0; i < mDrawables.size(); i++) {
+ mTmpBlurRegionsForFrame[i] = new BlurRegion(mDrawables.valueAt(i));
}
- mNeedsUpdate = false;
-
- if (mTmpBlurRegionsArray == null
- || mTmpBlurRegionsArray.length != mBlurRegions.size()) {
- mTmpBlurRegionsArray = new float[mBlurRegions.size()][];
- }
- if (DEBUG) {
- Log.d(TAG, "onBlurRegionUpdated will dispatch " + mTmpBlurRegionsArray.length
- + " regions for frame " + frameNumber);
- }
- for (int i = 0; i < mTmpBlurRegionsArray.length; i++) {
- mTmpBlurRegionsArray[i] = mBlurRegions.valueAt(i).toFloatArray();
- }
-
- mViewRoot.dispatchBlurRegions(mTmpBlurRegionsArray, frameNumber);
+ mHasUiUpdates = false;
}
+
+ return mTmpBlurRegionsForFrame;
+ }
+
+ /**
+ * Called on RenderThread.
+ *
+ * @return all blur regions if there are any ui or position updates for this frame,
+ * null otherwise
+ */
+ @VisibleForTesting
+ public float[][] getBlurRegionsToDispatchToSf(long frameNumber,
+ BlurRegion[] blurRegionsForFrame, boolean hasUiUpdatesForFrame) {
+ synchronized (mRtLock) {
+ if (!hasUiUpdatesForFrame && (mFrameRtUpdates.size() == 0
+ || mFrameRtUpdates.keyAt(0) > frameNumber)) {
+ return null;
+ }
+
+ // mFrameRtUpdates holds position updates coming from a thread pool span from
+ // RenderThread. At this point, all position updates for frame frameNumber should
+ // have been added to mFrameRtUpdates.
+ // Here, we apply all updates for frames <= frameNumber in case some previous update
+ // has been missed. This also protects mFrameRtUpdates from memory leaks.
+ while (mFrameRtUpdates.size() != 0 && mFrameRtUpdates.keyAt(0) <= frameNumber) {
+ final ArraySet<Runnable> frameUpdates = mFrameRtUpdates.valueAt(0);
+ mFrameRtUpdates.removeAt(0);
+ for (int i = 0; i < frameUpdates.size(); i++) {
+ frameUpdates.valueAt(i).run();
+ }
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Dispatching " + blurRegionsForFrame.length + " blur regions:");
+ }
+
+ final float[][] blurRegionsArray = new float[blurRegionsForFrame.length][];
+ for (int i = 0; i < blurRegionsArray.length; i++) {
+ blurRegionsArray[i] = blurRegionsForFrame[i].toFloatArray();
+ if (DEBUG) {
+ Log.d(TAG, blurRegionsForFrame[i].toString());
+ }
+ }
+ return blurRegionsArray;
+ }
+
+ /**
+ * Called on RenderThread in FrameDrawingCallback.
+ * Dispatch all blur regions if there are any ui or position updates.
+ */
+ public void dispatchBlurTransactionIfNeeded(long frameNumber,
+ BlurRegion[] blurRegionsForFrame, boolean hasUiUpdatesForFrame) {
+ final float[][] blurRegionsArray = getBlurRegionsToDispatchToSf(frameNumber,
+ blurRegionsForFrame, hasUiUpdatesForFrame);
+ if (blurRegionsArray != null) {
+ mViewRoot.dispatchBlurRegions(blurRegionsArray, frameNumber);
+ }
+ }
+
+ }
+
+ /**
+ * Wrapper for sending blur data to SurfaceFlinger
+ * Confined to RenderThread.
+ */
+ public static final class BlurRegion {
+ public final int blurRadius;
+ public final float cornerRadiusTL;
+ public final float cornerRadiusTR;
+ public final float cornerRadiusBL;
+ public final float cornerRadiusBR;
+ public final float alpha;
+ public final Rect rect;
+
+ BlurRegion(BackgroundBlurDrawable drawable) {
+ alpha = drawable.mAlpha;
+ blurRadius = drawable.mBlurRadius;
+ cornerRadiusTL = drawable.mCornerRadiusTL;
+ cornerRadiusTR = drawable.mCornerRadiusTR;
+ cornerRadiusBL = drawable.mCornerRadiusBL;
+ cornerRadiusBR = drawable.mCornerRadiusBR;
+ rect = drawable.mRect;
+ }
+
+ /**
+ * Serializes this class into a float array that's more JNI friendly.
+ */
+ float[] toFloatArray() {
+ final float[] floatArray = new float[10];
+ floatArray[0] = blurRadius;
+ floatArray[1] = alpha;
+ floatArray[2] = rect.left;
+ floatArray[3] = rect.top;
+ floatArray[4] = rect.right;
+ floatArray[5] = rect.bottom;
+ floatArray[6] = cornerRadiusTL;
+ floatArray[7] = cornerRadiusTR;
+ floatArray[8] = cornerRadiusBL;
+ floatArray[9] = cornerRadiusBR;
+ return floatArray;
+ }
+
+ @Override
+ public String toString() {
+ return "BlurRegion{"
+ + "blurRadius=" + blurRadius
+ + ", corners={" + cornerRadiusTL
+ + "," + cornerRadiusTR
+ + "," + cornerRadiusBL
+ + "," + cornerRadiusBR
+ + "}, alpha=" + alpha
+ + ", rect=" + rect
+ + "}";
}
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index bdb65f3..879e0a8 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -16,6 +16,8 @@
package com.android.internal.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.BatteryStats;
import android.os.Parcel;
import android.os.StatFs;
@@ -61,6 +63,7 @@
public static final String FILE_SUFFIX = ".bin";
private static final int MIN_FREE_SPACE = 100 * 1024 * 1024;
+ @Nullable
private final BatteryStatsImpl mStats;
private final Parcel mHistoryBuffer;
private final File mHistoryDir;
@@ -107,7 +110,8 @@
* @param systemDir typically /data/system
* @param historyBuffer The in-memory history buffer.
*/
- public BatteryStatsHistory(BatteryStatsImpl stats, File systemDir, Parcel historyBuffer) {
+ public BatteryStatsHistory(@NonNull BatteryStatsImpl stats, File systemDir,
+ Parcel historyBuffer) {
mStats = stats;
mHistoryBuffer = historyBuffer;
mHistoryDir = new File(systemDir, HISTORY_DIR);
@@ -149,11 +153,10 @@
/**
* Used when BatteryStatsImpl object is created from deserialization of a parcel,
* such as Settings app or checkin file.
- * @param stats BatteryStatsImpl object.
- * @param historyBuffer the history buffer inside BatteryStatsImpl
+ * @param historyBuffer the history buffer
*/
- public BatteryStatsHistory(BatteryStatsImpl stats, Parcel historyBuffer) {
- mStats = stats;
+ public BatteryStatsHistory(Parcel historyBuffer) {
+ mStats = null;
mHistoryDir = null;
mHistoryBuffer = historyBuffer;
}
@@ -184,10 +187,16 @@
* create next history file.
*/
public void startNextFile() {
+ if (mStats == null) {
+ Slog.wtf(TAG, "mStats should not be null when writing history");
+ return;
+ }
+
if (mFileNumbers.isEmpty()) {
Slog.wtf(TAG, "mFileNumbers should never be empty");
return;
}
+
// The last number in mFileNumbers is the highest number. The next file number is highest
// number plus one.
final int next = mFileNumbers.get(mFileNumbers.size() - 1) + 1;
@@ -357,7 +366,7 @@
private boolean skipHead(Parcel p) {
p.setDataPosition(0);
final int version = p.readInt();
- if (version != mStats.VERSION) {
+ if (version != BatteryStatsImpl.VERSION) {
return false;
}
// skip historyBaseTime field.
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
new file mode 100644
index 0000000..1871ac5
--- /dev/null
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -0,0 +1,264 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.util.Slog;
+
+import java.util.List;
+
+/**
+ * An iterator for {@link BatteryStats.HistoryItem}'s.
+ */
+public class BatteryStatsHistoryIterator {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "BatteryStatsHistoryItr";
+ private final BatteryStatsHistory mBatteryStatsHistory;
+ private final BatteryStats.HistoryStepDetails mReadHistoryStepDetails =
+ new BatteryStats.HistoryStepDetails();
+ private final String[] mReadHistoryStrings;
+ private final int[] mReadHistoryUids;
+
+ public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
+ @NonNull List<BatteryStats.HistoryTag> historyTagPool) {
+ mBatteryStatsHistory = history;
+
+ mBatteryStatsHistory.startIteratingHistory();
+
+ mReadHistoryStrings = new String[historyTagPool.size()];
+ mReadHistoryUids = new int[historyTagPool.size()];
+ for (int i = historyTagPool.size() - 1; i >= 0; i--) {
+ BatteryStats.HistoryTag tag = historyTagPool.get(i);
+ final int idx = tag.poolIdx;
+ mReadHistoryStrings[idx] = tag.string;
+ mReadHistoryUids[idx] = tag.uid;
+ }
+ }
+
+ /**
+ * Retrieves the next HistoryItem from battery history, if available. Returns false if there
+ * are no more items.
+ */
+ public boolean next(BatteryStats.HistoryItem out) {
+ Parcel p = mBatteryStatsHistory.getNextParcel(out);
+ if (p == null) {
+ mBatteryStatsHistory.finishIteratingHistory();
+ return false;
+ }
+
+ final long lastRealtimeMs = out.time;
+ final long lastWalltimeMs = out.currentTime;
+ readHistoryDelta(p, out);
+ if (out.cmd != BatteryStats.HistoryItem.CMD_CURRENT_TIME
+ && out.cmd != BatteryStats.HistoryItem.CMD_RESET && lastWalltimeMs != 0) {
+ out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs);
+ }
+ return true;
+ }
+
+ void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) {
+ int firstToken = src.readInt();
+ int deltaTimeToken = firstToken & BatteryStatsImpl.DELTA_TIME_MASK;
+ cur.cmd = BatteryStats.HistoryItem.CMD_UPDATE;
+ cur.numReadInts = 1;
+ if (DEBUG) {
+ Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ + " deltaTimeToken=" + deltaTimeToken);
+ }
+
+ if (deltaTimeToken < BatteryStatsImpl.DELTA_TIME_ABS) {
+ cur.time += deltaTimeToken;
+ } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_ABS) {
+ cur.readFromParcel(src);
+ if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
+ return;
+ } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_INT) {
+ int delta = src.readInt();
+ cur.time += delta;
+ cur.numReadInts += 1;
+ if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
+ } else {
+ long delta = src.readLong();
+ if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
+ cur.time += delta;
+ cur.numReadInts += 2;
+ }
+
+ final int batteryLevelInt;
+ if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_LEVEL_FLAG) != 0) {
+ batteryLevelInt = src.readInt();
+ readBatteryLevelInt(batteryLevelInt, cur);
+ cur.numReadInts += 1;
+ if (DEBUG) {
+ Slog.i(TAG, "READ DELTA: batteryToken=0x"
+ + Integer.toHexString(batteryLevelInt)
+ + " batteryLevel=" + cur.batteryLevel
+ + " batteryTemp=" + cur.batteryTemperature
+ + " batteryVolt=" + (int) cur.batteryVoltage);
+ }
+ } else {
+ batteryLevelInt = 0;
+ }
+
+ if ((firstToken & BatteryStatsImpl.DELTA_STATE_FLAG) != 0) {
+ int stateInt = src.readInt();
+ cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (stateInt
+ & (~BatteryStatsImpl.STATE_BATTERY_MASK));
+ cur.batteryStatus = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_STATUS_SHIFT)
+ & BatteryStatsImpl.STATE_BATTERY_STATUS_MASK);
+ cur.batteryHealth = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_HEALTH_SHIFT)
+ & BatteryStatsImpl.STATE_BATTERY_HEALTH_MASK);
+ cur.batteryPlugType = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_PLUG_SHIFT)
+ & BatteryStatsImpl.STATE_BATTERY_PLUG_MASK);
+ switch (cur.batteryPlugType) {
+ case 1:
+ cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
+ break;
+ case 2:
+ cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
+ break;
+ case 3:
+ cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
+ break;
+ }
+ cur.numReadInts += 1;
+ if (DEBUG) {
+ Slog.i(TAG, "READ DELTA: stateToken=0x"
+ + Integer.toHexString(stateInt)
+ + " batteryStatus=" + cur.batteryStatus
+ + " batteryHealth=" + cur.batteryHealth
+ + " batteryPlugType=" + cur.batteryPlugType
+ + " states=0x" + Integer.toHexString(cur.states));
+ }
+ } else {
+ cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (cur.states
+ & (~BatteryStatsImpl.STATE_BATTERY_MASK));
+ }
+
+ if ((firstToken & BatteryStatsImpl.DELTA_STATE2_FLAG) != 0) {
+ cur.states2 = src.readInt();
+ if (DEBUG) {
+ Slog.i(TAG, "READ DELTA: states2=0x"
+ + Integer.toHexString(cur.states2));
+ }
+ }
+
+ if ((firstToken & BatteryStatsImpl.DELTA_WAKELOCK_FLAG) != 0) {
+ int indexes = src.readInt();
+ int wakeLockIndex = indexes & 0xffff;
+ int wakeReasonIndex = (indexes >> 16) & 0xffff;
+ if (wakeLockIndex != 0xffff) {
+ cur.wakelockTag = cur.localWakelockTag;
+ readHistoryTag(wakeLockIndex, cur.wakelockTag);
+ if (DEBUG) {
+ Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+ + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
+ }
+ } else {
+ cur.wakelockTag = null;
+ }
+ if (wakeReasonIndex != 0xffff) {
+ cur.wakeReasonTag = cur.localWakeReasonTag;
+ readHistoryTag(wakeReasonIndex, cur.wakeReasonTag);
+ if (DEBUG) {
+ Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
+ + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
+ }
+ } else {
+ cur.wakeReasonTag = null;
+ }
+ cur.numReadInts += 1;
+ } else {
+ cur.wakelockTag = null;
+ cur.wakeReasonTag = null;
+ }
+
+ if ((firstToken & BatteryStatsImpl.DELTA_EVENT_FLAG) != 0) {
+ cur.eventTag = cur.localEventTag;
+ final int codeAndIndex = src.readInt();
+ cur.eventCode = (codeAndIndex & 0xffff);
+ final int index = ((codeAndIndex >> 16) & 0xffff);
+ readHistoryTag(index, cur.eventTag);
+ cur.numReadInts += 1;
+ if (DEBUG) {
+ Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
+ + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+ + cur.eventTag.string);
+ }
+ } else {
+ cur.eventCode = BatteryStats.HistoryItem.EVENT_NONE;
+ }
+
+ if ((batteryLevelInt & BatteryStatsImpl.BATTERY_DELTA_LEVEL_FLAG) != 0) {
+ cur.stepDetails = mReadHistoryStepDetails;
+ cur.stepDetails.readFromParcel(src);
+ } else {
+ cur.stepDetails = null;
+ }
+
+ if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_CHARGE_FLAG) != 0) {
+ cur.batteryChargeUah = src.readInt();
+ }
+ cur.modemRailChargeMah = src.readDouble();
+ cur.wifiRailChargeMah = src.readDouble();
+ }
+
+ int getHistoryStringPoolSize() {
+ return mReadHistoryStrings.length;
+ }
+
+ int getHistoryStringPoolBytes() {
+ int totalChars = 0;
+ for (int i = mReadHistoryStrings.length - 1; i >= 0; i--) {
+ if (mReadHistoryStrings[i] != null) {
+ totalChars += mReadHistoryStrings[i].length() + 1;
+ }
+ }
+
+ // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
+ // Each string character is 2 bytes.
+ return (mReadHistoryStrings.length * 12) + (totalChars * 2);
+ }
+
+ String getHistoryTagPoolString(int index) {
+ return mReadHistoryStrings[index];
+ }
+
+ int getHistoryTagPoolUid(int index) {
+ return mReadHistoryUids[index];
+ }
+
+ private void readHistoryTag(int index, BatteryStats.HistoryTag tag) {
+ if (index < mReadHistoryStrings.length) {
+ tag.string = mReadHistoryStrings[index];
+ tag.uid = mReadHistoryUids[index];
+ } else {
+ tag.string = null;
+ tag.uid = 0;
+ }
+ tag.poolIdx = index;
+ }
+
+ private static void readBatteryLevelInt(int batteryLevelInt, BatteryStats.HistoryItem out) {
+ out.batteryLevel = (byte) ((batteryLevelInt & 0xfe000000) >>> 25);
+ out.batteryTemperature = (short) ((batteryLevelInt & 0x01ff8000) >>> 15);
+ out.batteryVoltage = (char) ((batteryLevelInt & 0x00007ffe) >>> 1);
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 54095bd..73527d4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -81,7 +81,6 @@
import android.util.IntArray;
import android.util.KeyValueListParser;
import android.util.Log;
-import android.util.LogWriter;
import android.util.LongSparseArray;
import android.util.LongSparseLongArray;
import android.util.MutableInt;
@@ -108,7 +107,6 @@
import com.android.internal.power.MeasuredEnergyStats;
import com.android.internal.power.MeasuredEnergyStats.StandardEnergyBucket;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.net.module.util.NetworkCapabilitiesUtils;
@@ -164,7 +162,6 @@
private static final boolean DEBUG_BINDER_STATS = false;
private static final boolean DEBUG_MEMORY = false;
private static final boolean DEBUG_HISTORY = false;
- private static final boolean USE_OLD_HISTORY = false; // for debugging.
// TODO: remove "tcp" from network methods, since we measure total stats.
@@ -172,7 +169,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 193 + (USE_OLD_HISTORY ? 1000 : 0);
+ static final int VERSION = 193;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -740,15 +737,11 @@
protected boolean mRecordingHistory = false;
int mNumHistoryItems;
+ final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
final Parcel mHistoryBuffer = Parcel.obtain();
final HistoryItem mHistoryLastWritten = new HistoryItem();
final HistoryItem mHistoryLastLastWritten = new HistoryItem();
- final HistoryItem mHistoryReadTmp = new HistoryItem();
final HistoryItem mHistoryAddTmp = new HistoryItem();
- final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
- String[] mReadHistoryStrings;
- int[] mReadHistoryUids;
- int mReadHistoryChars;
int mNextHistoryTagIdx = 0;
int mNumHistoryTagChars = 0;
int mHistoryBufferLastPos = -1;
@@ -789,6 +782,7 @@
private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION
? new HashMap<>() : null;
+ @NonNull
final BatteryStatsHistory mBatteryStatsHistory;
final HistoryItem mHistoryCur = new HistoryItem();
@@ -831,9 +825,9 @@
long mCurStepStatSoftIrqTimeMs;
long mCurStepStatIdleTimeMs;
+ private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator;
private HistoryItem mHistoryIterator;
private boolean mReadOverflow;
- private boolean mIteratingHistory;
int mStartCount;
@@ -1197,7 +1191,7 @@
mStatsFile = null;
mCheckinFile = null;
mDailyFile = null;
- mBatteryStatsHistory = null;
+ mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
mHandler = null;
mPlatformIdleStateCallback = null;
mMeasuredEnergyRetriever = null;
@@ -3244,17 +3238,6 @@
return idx;
}
- private void readHistoryTag(int index, HistoryTag tag) {
- if (index < mReadHistoryStrings.length) {
- tag.string = mReadHistoryStrings[index];
- tag.uid = mReadHistoryUids[index];
- } else {
- tag.string = null;
- tag.uid = 0;
- }
- tag.poolIdx = index;
- }
-
/*
The history delta format uses flags to denote further data in subsequent ints in the parcel.
@@ -3631,137 +3614,6 @@
mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
}
- public void readHistoryDelta(Parcel src, HistoryItem cur) {
- int firstToken = src.readInt();
- int deltaTimeToken = firstToken&DELTA_TIME_MASK;
- cur.cmd = HistoryItem.CMD_UPDATE;
- cur.numReadInts = 1;
- if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
- + " deltaTimeToken=" + deltaTimeToken);
-
- if (deltaTimeToken < DELTA_TIME_ABS) {
- cur.time += deltaTimeToken;
- } else if (deltaTimeToken == DELTA_TIME_ABS) {
- cur.readFromParcel(src);
- if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
- return;
- } else if (deltaTimeToken == DELTA_TIME_INT) {
- int delta = src.readInt();
- cur.time += delta;
- cur.numReadInts += 1;
- if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
- } else {
- long delta = src.readLong();
- if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
- cur.time += delta;
- cur.numReadInts += 2;
- }
-
- final int batteryLevelInt;
- if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
- batteryLevelInt = src.readInt();
- readBatteryLevelInt(batteryLevelInt, cur);
- cur.numReadInts += 1;
- if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"
- + Integer.toHexString(batteryLevelInt)
- + " batteryLevel=" + cur.batteryLevel
- + " batteryTemp=" + cur.batteryTemperature
- + " batteryVolt=" + (int)cur.batteryVoltage);
- } else {
- batteryLevelInt = 0;
- }
-
- if ((firstToken&DELTA_STATE_FLAG) != 0) {
- int stateInt = src.readInt();
- cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~STATE_BATTERY_MASK));
- cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
- & STATE_BATTERY_STATUS_MASK);
- cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
- & STATE_BATTERY_HEALTH_MASK);
- cur.batteryPlugType = (byte)((stateInt>>STATE_BATTERY_PLUG_SHIFT)
- & STATE_BATTERY_PLUG_MASK);
- switch (cur.batteryPlugType) {
- case 1:
- cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
- break;
- case 2:
- cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
- break;
- case 3:
- cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
- break;
- }
- cur.numReadInts += 1;
- if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
- + Integer.toHexString(stateInt)
- + " batteryStatus=" + cur.batteryStatus
- + " batteryHealth=" + cur.batteryHealth
- + " batteryPlugType=" + cur.batteryPlugType
- + " states=0x" + Integer.toHexString(cur.states));
- } else {
- cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~STATE_BATTERY_MASK));
- }
-
- if ((firstToken&DELTA_STATE2_FLAG) != 0) {
- cur.states2 = src.readInt();
- if (DEBUG) Slog.i(TAG, "READ DELTA: states2=0x"
- + Integer.toHexString(cur.states2));
- }
-
- if ((firstToken&DELTA_WAKELOCK_FLAG) != 0) {
- int indexes = src.readInt();
- int wakeLockIndex = indexes&0xffff;
- int wakeReasonIndex = (indexes>>16)&0xffff;
- if (wakeLockIndex != 0xffff) {
- cur.wakelockTag = cur.localWakelockTag;
- readHistoryTag(wakeLockIndex, cur.wakelockTag);
- if (DEBUG) Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
- + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
- } else {
- cur.wakelockTag = null;
- }
- if (wakeReasonIndex != 0xffff) {
- cur.wakeReasonTag = cur.localWakeReasonTag;
- readHistoryTag(wakeReasonIndex, cur.wakeReasonTag);
- if (DEBUG) Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
- + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
- } else {
- cur.wakeReasonTag = null;
- }
- cur.numReadInts += 1;
- } else {
- cur.wakelockTag = null;
- cur.wakeReasonTag = null;
- }
-
- if ((firstToken&DELTA_EVENT_FLAG) != 0) {
- cur.eventTag = cur.localEventTag;
- final int codeAndIndex = src.readInt();
- cur.eventCode = (codeAndIndex&0xffff);
- final int index = ((codeAndIndex>>16)&0xffff);
- readHistoryTag(index, cur.eventTag);
- cur.numReadInts += 1;
- if (DEBUG) Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
- + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
- + cur.eventTag.string);
- } else {
- cur.eventCode = HistoryItem.EVENT_NONE;
- }
-
- if ((batteryLevelInt&BATTERY_DELTA_LEVEL_FLAG) != 0) {
- cur.stepDetails = mReadHistoryStepDetails;
- cur.stepDetails.readFromParcel(src);
- } else {
- cur.stepDetails = null;
- }
-
- if ((firstToken&DELTA_BATTERY_CHARGE_FLAG) != 0) {
- cur.batteryChargeUah = src.readInt();
- }
- cur.modemRailChargeMah = src.readDouble();
- cur.wifiRailChargeMah = src.readDouble();
- }
-
@Override
public void commitCurrentHistoryBatchLocked() {
mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
@@ -3873,7 +3725,7 @@
}
private void addHistoryBufferLocked(long elapsedRealtimeMs, byte cmd, HistoryItem cur) {
- if (mIteratingHistory) {
+ if (mBatteryStatsHistoryIterator != null) {
throw new IllegalStateException("Can't do this while iterating history!");
}
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
@@ -3917,44 +3769,6 @@
void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, cur);
-
- if (!USE_OLD_HISTORY) {
- return;
- }
-
- if (!mHaveBatteryLevel || !mRecordingHistory) {
- return;
- }
-
- // If the current time is basically the same as the last time,
- // and no states have since the last recorded entry changed and
- // are now resetting back to their original value, then just collapse
- // into one record.
- if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
- && (mHistoryBaseTimeMs + elapsedRealtimeMs) < (mHistoryEnd.time + 1000)
- && ((mHistoryEnd.states^cur.states)&mChangedStates&mActiveHistoryStates) == 0
- && ((mHistoryEnd.states2^cur.states2)&mChangedStates2&mActiveHistoryStates2) == 0) {
- // If the current is the same as the one before, then we no
- // longer need the entry.
- if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
- && (mHistoryBaseTimeMs + elapsedRealtimeMs) < (mHistoryEnd.time + 500)
- && mHistoryLastEnd.sameNonEvent(cur)) {
- mHistoryLastEnd.next = null;
- mHistoryEnd.next = mHistoryCache;
- mHistoryCache = mHistoryEnd;
- mHistoryEnd = mHistoryLastEnd;
- mHistoryLastEnd = null;
- } else {
- mChangedStates |= mHistoryEnd.states^(cur.states&mActiveHistoryStates);
- mChangedStates2 |= mHistoryEnd.states^(cur.states2&mActiveHistoryStates2);
- mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, cur);
- }
- return;
- }
-
- mChangedStates = 0;
- mChangedStates2 = 0;
- addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur);
}
public void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code,
@@ -3992,15 +3806,6 @@
void clearHistoryLocked() {
if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!");
- if (USE_OLD_HISTORY) {
- if (mHistory != null) {
- mHistoryEnd.next = mHistoryCache;
- mHistoryCache = mHistory;
- mHistory = mHistoryLastEnd = mHistoryEnd = null;
- }
- mNumHistoryItems = 0;
- }
-
mHistoryBaseTimeMs = 0;
mLastHistoryElapsedRealtimeMs = 0;
mTrackRunningHistoryElapsedRealtimeMs = 0;
@@ -7965,16 +7770,14 @@
/** Adds the given energy to the given standard energy bucket for this uid. */
private void addEnergyToStandardBucketLocked(long energyDeltaUJ,
- @StandardEnergyBucket int energyBucket, boolean accumulate) {
+ @StandardEnergyBucket int energyBucket) {
getOrCreateMeasuredEnergyStatsLocked()
- .updateStandardBucket(energyBucket, energyDeltaUJ, accumulate);
+ .updateStandardBucket(energyBucket, energyDeltaUJ);
}
/** Adds the given energy to the given custom energy bucket for this uid. */
- private void addEnergyToCustomBucketLocked(long energyDeltaUJ, int energyBucket,
- boolean accumulate) {
- getOrCreateMeasuredEnergyStatsLocked()
- .updateCustomBucket(energyBucket, energyDeltaUJ, accumulate);
+ private void addEnergyToCustomBucketLocked(long energyDeltaUJ, int energyBucket) {
+ getOrCreateMeasuredEnergyStatsLocked().updateCustomBucket(energyBucket, energyDeltaUJ);
}
/**
@@ -10733,7 +10536,7 @@
if (systemDir == null) {
mStatsFile = null;
- mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
+ mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
} else {
mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin"));
mBatteryStatsHistory = new BatteryStatsHistory(this, systemDir, mHistoryBuffer);
@@ -10855,7 +10658,7 @@
mExternalSync = null;
mConstants = new Constants(mHandler);
clearHistoryLocked();
- mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
+ mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
readFromParcel(p);
mPlatformIdleStateCallback = null;
mMeasuredEnergyRetriever = null;
@@ -11222,60 +11025,6 @@
return mNextMaxDailyDeadlineMs;
}
- @Override
- public boolean startIteratingOldHistoryLocked() {
- if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
- + " pos=" + mHistoryBuffer.dataPosition());
- if ((mHistoryIterator = mHistory) == null) {
- return false;
- }
- mHistoryBuffer.setDataPosition(0);
- mHistoryReadTmp.clear();
- mReadOverflow = false;
- mIteratingHistory = true;
- return true;
- }
-
- @Override
- public boolean getNextOldHistoryLocked(HistoryItem out) {
- boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
- if (!end) {
- readHistoryDelta(mHistoryBuffer, mHistoryReadTmp);
- mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
- }
- HistoryItem cur = mHistoryIterator;
- if (cur == null) {
- if (!mReadOverflow && !end) {
- Slog.w(TAG, "Old history ends before new history!");
- }
- return false;
- }
- out.setTo(cur);
- mHistoryIterator = cur.next;
- if (!mReadOverflow) {
- if (end) {
- Slog.w(TAG, "New history ends before old history!");
- } else if (!out.same(mHistoryReadTmp)) {
- PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
- pw.println("Histories differ!");
- pw.println("Old history:");
- (new HistoryPrinter()).printNextItem(pw, out, 0, false, true);
- pw.println("New history:");
- (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, 0, false,
- true);
- pw.flush();
- }
- }
- return true;
- }
-
- @Override
- public void finishIteratingOldHistoryLocked() {
- mIteratingHistory = false;
- mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
- mHistoryIterator = null;
- }
-
public int getHistoryTotalSize() {
return mConstants.MAX_HISTORY_BUFFER * mConstants.MAX_HISTORY_FILES;
}
@@ -11287,67 +11036,55 @@
@Override
@UnsupportedAppUsage
public boolean startIteratingHistoryLocked() {
- mBatteryStatsHistory.startIteratingHistory();
mReadOverflow = false;
- mIteratingHistory = true;
- mReadHistoryStrings = new String[mHistoryTagPool.size()];
- mReadHistoryUids = new int[mHistoryTagPool.size()];
- mReadHistoryChars = 0;
- for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
- final HistoryTag tag = ent.getKey();
- final int idx = ent.getValue();
- mReadHistoryStrings[idx] = tag.string;
- mReadHistoryUids[idx] = tag.uid;
- mReadHistoryChars += tag.string.length() + 1;
- }
+ mBatteryStatsHistoryIterator = createBatteryStatsHistoryIterator();
return true;
}
+ /**
+ * Creates an iterator for battery stats history.
+ */
+ @VisibleForTesting
+ public BatteryStatsHistoryIterator createBatteryStatsHistoryIterator() {
+ ArrayList<HistoryTag> tags = new ArrayList<>(mHistoryTagPool.size());
+ for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) {
+ final HistoryTag tag = entry.getKey();
+ tag.poolIdx = entry.getValue();
+ tags.add(tag);
+ }
+
+ return new BatteryStatsHistoryIterator(mBatteryStatsHistory, tags);
+ }
+
@Override
public int getHistoryStringPoolSize() {
- return mReadHistoryStrings.length;
+ return mBatteryStatsHistoryIterator.getHistoryStringPoolSize();
}
@Override
public int getHistoryStringPoolBytes() {
- // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
- // Each string character is 2 bytes.
- return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2);
+ return mBatteryStatsHistoryIterator.getHistoryStringPoolBytes();
}
@Override
public String getHistoryTagPoolString(int index) {
- return mReadHistoryStrings[index];
+ return mBatteryStatsHistoryIterator.getHistoryTagPoolString(index);
}
@Override
public int getHistoryTagPoolUid(int index) {
- return mReadHistoryUids[index];
+ return mBatteryStatsHistoryIterator.getHistoryTagPoolUid(index);
}
@Override
@UnsupportedAppUsage
public boolean getNextHistoryLocked(HistoryItem out) {
- Parcel p = mBatteryStatsHistory.getNextParcel(out);
- if (p == null) {
- return false;
- }
- final long lastRealtimeMs = out.time;
- final long lastWalltimeMs = out.currentTime;
- readHistoryDelta(p, out);
- if (out.cmd != HistoryItem.CMD_CURRENT_TIME
- && out.cmd != HistoryItem.CMD_RESET && lastWalltimeMs != 0) {
- out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs);
- }
- return true;
+ return mBatteryStatsHistoryIterator.next(out);
}
@Override
public void finishIteratingHistoryLocked() {
- mBatteryStatsHistory.finishIteratingHistory();
- mIteratingHistory = false;
- mReadHistoryStrings = null;
- mReadHistoryUids = null;
+ mBatteryStatsHistoryIterator = null;
}
@Override
@@ -12468,7 +12205,7 @@
return;
}
- mGlobalMeasuredEnergyStats.updateStandardBucket(energyBucket, energyUJ, true);
+ mGlobalMeasuredEnergyStats.updateStandardBucket(energyBucket, energyUJ);
// Now we blame individual apps, but only if the display was ON.
if (energyBucket != MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON) {
@@ -12506,7 +12243,7 @@
final long appDisplayEnergyMJ =
(totalDisplayEnergyMJ * fgTimeMs + (totalFgTimeMs / 2))
/ totalFgTimeMs;
- uid.addEnergyToStandardBucketLocked(appDisplayEnergyMJ * 1000, energyBucket, true);
+ uid.addEnergyToStandardBucketLocked(appDisplayEnergyMJ * 1000, energyBucket);
// To mitigate round-off errors, remove this app from numerator & denominator totals
totalDisplayEnergyMJ -= appDisplayEnergyMJ;
@@ -12533,7 +12270,7 @@
if (mGlobalMeasuredEnergyStats == null) return;
if (!mOnBatteryInternal || mIgnoreNextExternalStats || totalEnergyUJ <= 0) return;
- mGlobalMeasuredEnergyStats.updateCustomBucket(customEnergyBucket, totalEnergyUJ, true);
+ mGlobalMeasuredEnergyStats.updateCustomBucket(customEnergyBucket, totalEnergyUJ);
if (uidEnergies == null) return;
final int numUids = uidEnergies.size();
@@ -12543,7 +12280,7 @@
if (uidEnergyUJ == 0) continue;
final Uid uidObj = getAvailableUidStatsLocked(uidInt);
if (uidObj != null) {
- uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket, true);
+ uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket);
} else {
// Ignore any uid not already known to BatteryStats, rather than creating a new Uid.
// Otherwise we could end up reviving dead Uids. Note that the CPU data is updated
@@ -14637,7 +14374,7 @@
Parcel p = Parcel.obtain();
final long start = SystemClock.uptimeMillis();
- writeHistoryBuffer(p, true, true);
+ writeHistoryBuffer(p, true);
if (DEBUG) {
Slog.d(TAG, "writeHistoryBuffer duration ms:"
+ (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
@@ -14731,7 +14468,7 @@
if (raw.length > 0) {
history.unmarshall(raw, 0, raw.length);
history.setDataPosition(0);
- readHistoryBuffer(history, true);
+ readHistoryBuffer(history);
}
if (DEBUG) {
Slog.d(TAG, "readLocked history file::"
@@ -14755,10 +14492,6 @@
mRecordingHistory = true;
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
final long uptimeMs = mClocks.uptimeMillis();
- if (USE_OLD_HISTORY) {
- addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs,
- HistoryItem.CMD_START, mHistoryCur);
- }
addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_START, mHistoryCur);
startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
}
@@ -14770,7 +14503,7 @@
return 0;
}
- void readHistoryBuffer(Parcel in, boolean andOldHistory) throws ParcelFormatException {
+ void readHistoryBuffer(Parcel in) throws ParcelFormatException {
final int version = in.readInt();
if (version != VERSION) {
Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
@@ -14798,10 +14531,6 @@
in.setDataPosition(curPos + bufSize);
}
- if (andOldHistory) {
- readOldHistory(in);
- }
-
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** OLD mHistoryBaseTimeMs: ");
@@ -14830,18 +14559,7 @@
}
}
- void readOldHistory(Parcel in) {
- if (!USE_OLD_HISTORY) {
- return;
- }
- mHistory = mHistoryEnd = mHistoryCache = null;
- while (in.dataAvail() > 0) {
- HistoryItem rec = new HistoryItem(in);
- addHistoryRecordLocked(rec);
- }
- }
-
- void writeHistoryBuffer(Parcel out, boolean inclData, boolean andOldHistory) {
+ void writeHistoryBuffer(Parcel out, boolean inclData) {
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** WRITING mHistoryBaseTimeMs: ");
@@ -14862,22 +14580,6 @@
if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
+ mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
-
- if (andOldHistory) {
- writeOldHistory(out);
- }
- }
-
- void writeOldHistory(Parcel out) {
- if (!USE_OLD_HISTORY) {
- return;
- }
- HistoryItem rec = mHistory;
- while (rec != null) {
- if (rec.time >= 0) rec.writeToParcel(out, 0);
- rec = rec.next;
- }
- out.writeLong(-1);
}
public void readSummaryFromParcel(Parcel in) throws ParcelFormatException {
@@ -14890,7 +14592,7 @@
boolean inclHistory = in.readBoolean();
if (inclHistory) {
- readHistoryBuffer(in, true);
+ readHistoryBuffer(in);
mBatteryStatsHistory.readFromParcel(in);
}
@@ -15409,7 +15111,7 @@
out.writeBoolean(inclHistory);
if (inclHistory) {
- writeHistoryBuffer(out, true, true);
+ writeHistoryBuffer(out, true);
mBatteryStatsHistory.writeToParcel(out);
}
@@ -15922,7 +15624,7 @@
throw new ParcelFormatException("Bad magic number: #" + Integer.toHexString(magic));
}
- readHistoryBuffer(in, false);
+ readHistoryBuffer(in);
mBatteryStatsHistory.readFromParcel(in);
mStartCount = in.readInt();
@@ -16161,7 +15863,7 @@
out.writeInt(MAGIC);
- writeHistoryBuffer(out, true, false);
+ writeHistoryBuffer(out, true);
mBatteryStatsHistory.writeToParcel(out);
out.writeInt(mStartCount);
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index eef9fa7..15b584d 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -22,12 +22,15 @@
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Bundle;
-import android.os.SystemClock;
+import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Uses accumulated battery stats data and PowerCalculators to produce power
@@ -85,7 +88,7 @@
}
/**
- * Returns a snapshot of battery attribution data.
+ * Returns snapshots of battery attribution data, one per supplied query.
*/
public List<BatteryUsageStats> getBatteryUsageStats(List<BatteryUsageStatsQuery> queries) {
@@ -112,12 +115,19 @@
return results;
}
- private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
+ /**
+ * Returns a snapshot of battery attribution data.
+ */
+ @VisibleForTesting
+ public BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
+ final long realtimeUs = mStats.mClocks.elapsedRealtime() * 1000;
+ final long uptimeUs = mStats.mClocks.uptimeMillis() * 1000;
+
final long[] customMeasuredEnergiesMicroJoules =
mStats.getCustomMeasuredEnergiesMicroJoules();
final int customPowerComponentCount = customMeasuredEnergiesMicroJoules != null
- ? customMeasuredEnergiesMicroJoules.length
- : 0;
+ ? customMeasuredEnergiesMicroJoules.length
+ : 0;
// TODO(b/174186358): read extra time component number from configuration
final int customTimeComponentCount = 0;
@@ -128,12 +138,14 @@
SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
for (int i = uidStats.size() - 1; i >= 0; i--) {
- batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
+ final BatteryStats.Uid uid = uidStats.valueAt(i);
+ batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid)
+ .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND,
+ getProcessBackgroundTimeMs(uid, realtimeUs))
+ .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND,
+ getProcessForegroundTimeMs(uid, realtimeUs));
}
- final long realtimeUs = SystemClock.elapsedRealtime() * 1000;
- final long uptimeUs = SystemClock.uptimeMillis() * 1000;
-
final List<PowerCalculator> powerCalculators = getPowerCalculators();
for (int i = 0, count = powerCalculators.size(); i < count; i++) {
PowerCalculator powerCalculator = powerCalculators.get(i);
@@ -141,6 +153,51 @@
query);
}
+ if ((query.getFlags()
+ & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
+ ArrayList<BatteryStats.HistoryTag> tags = new ArrayList<>(
+ mStats.mHistoryTagPool.size());
+ for (Map.Entry<BatteryStats.HistoryTag, Integer> entry :
+ mStats.mHistoryTagPool.entrySet()) {
+ final BatteryStats.HistoryTag tag = entry.getKey();
+ tag.poolIdx = entry.getValue();
+ tags.add(tag);
+ }
+
+ batteryUsageStatsBuilder.setBatteryHistory(mStats.mHistoryBuffer, tags);
+ }
+
return batteryUsageStatsBuilder.build();
}
+
+ private long getProcessForegroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
+ final long topStateDurationMs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP,
+ realtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000;
+
+ long foregroundActivityDurationMs = 0;
+ final BatteryStats.Timer foregroundActivityTimer = uid.getForegroundActivityTimer();
+ if (foregroundActivityTimer != null) {
+ foregroundActivityDurationMs = foregroundActivityTimer.getTotalTimeLocked(realtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ }
+
+ // Use the min value of STATE_TOP time and foreground activity time, since both of these
+ // times are imprecise
+ final long foregroundDurationMs = Math.min(topStateDurationMs,
+ foregroundActivityDurationMs);
+
+ long foregroundServiceDurationMs = 0;
+ final BatteryStats.Timer foregroundServiceTimer = uid.getForegroundServiceTimer();
+ if (foregroundServiceTimer != null) {
+ foregroundServiceDurationMs = foregroundServiceTimer.getTotalTimeLocked(realtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ }
+
+ return foregroundDurationMs + foregroundServiceDurationMs;
+ }
+
+ private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
+ return uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND, realtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ }
}
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index 4299f09..64c68ce 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -152,6 +152,10 @@
*/
public void removeUid(int uid) {
mLastTimes.delete(uid);
+
+ if (mBpfTimesAvailable) {
+ mBpfReader.removeUidsInRange(uid, uid);
+ }
}
/**
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index 9698f19..791e9ad 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -1,6 +1,23 @@
{
"presubmit": [
{
+ "file_patterns": ["Battery[^/]*\\.java"],
+ "name": "FrameworksCoreTests",
+ "options": [
+ { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+ { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+ ]
+ },
+ {
+ "file_patterns": ["Battery[^/]*\\.java"],
+ "name": "FrameworksServicesTests",
+ "options": [
+ { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+ { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+ { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+ ]
+ },
+ {
"name": "FrameworksCoreTests",
"options": [
{
diff --git a/core/java/com/android/internal/os/UsageBasedPowerEstimator.java b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
index 5910b61..fd52014 100644
--- a/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
+++ b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
@@ -32,6 +32,10 @@
mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR;
}
+ public boolean isSupported() {
+ return mAveragePowerMahPerMs != 0;
+ }
+
/**
* Given a {@link BatteryStats.Timer}, returns the accumulated duration.
*/
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 63763f7..98f613f 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -15,8 +15,13 @@
*/
package com.android.internal.os;
+import android.os.BatteryConsumer;
import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
@@ -30,25 +35,93 @@
public class WifiPowerCalculator extends PowerCalculator {
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
private static final String TAG = "WifiPowerCalculator";
- private final double mIdleCurrentMa;
- private final double mTxCurrentMa;
- private final double mRxCurrentMa;
- private final PowerProfile mPowerProfile;
+ private final UsageBasedPowerEstimator mIdlePowerEstimator;
+ private final UsageBasedPowerEstimator mTxPowerEstimator;
+ private final UsageBasedPowerEstimator mRxPowerEstimator;
+ private final UsageBasedPowerEstimator mPowerOnPowerEstimator;
+ private final UsageBasedPowerEstimator mScanPowerEstimator;
+ private final UsageBasedPowerEstimator mBatchScanPowerEstimator;
private final boolean mHasWifiPowerController;
- private double mTotalAppPowerDrain = 0;
- private long mTotalAppRunningTime = 0;
- private WifiPowerEstimator mWifiPowerEstimator;
- private boolean mHasWifiPowerReporting;
+ private final double mWifiPowerPerPacket;
+
+ private static class PowerDurationAndTraffic {
+ public double powerMah;
+ public long durationMs;
+
+ public long wifiRxPackets;
+ public long wifiTxPackets;
+ public long wifiRxBytes;
+ public long wifiTxBytes;
+ }
public WifiPowerCalculator(PowerProfile profile) {
- mPowerProfile = profile;
+ mPowerOnPowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_WIFI_ON));
+ mScanPowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN));
+ mBatchScanPowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN));
+ mIdlePowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE));
+ mTxPowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX));
+ mRxPowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX));
- mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
- mTxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX);
- mRxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX);
+ mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
- mHasWifiPowerController = mIdleCurrentMa != 0 && mTxCurrentMa != 0 && mRxCurrentMa != 0;
- mWifiPowerEstimator = new WifiPowerEstimator(mPowerProfile);
+ mHasWifiPowerController =
+ mIdlePowerEstimator.isSupported() && mTxPowerEstimator.isSupported()
+ && mRxPowerEstimator.isSupported();
+ }
+
+ @Override
+ public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+
+ // batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
+ // so always check this field.
+ final boolean hasWifiPowerReporting =
+ mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
+
+ final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
+ builder.getOrCreateSystemBatteryConsumerBuilder(
+ SystemBatteryConsumer.DRAIN_TYPE_WIFI);
+
+ long totalAppDurationMs = 0;
+ double totalAppPowerMah = 0;
+ final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
+ final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+ builder.getUidBatteryConsumerBuilders();
+ for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+ final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+ calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED,
+ hasWifiPowerReporting);
+
+ totalAppDurationMs += powerDurationAndTraffic.durationMs;
+ totalAppPowerMah += powerDurationAndTraffic.powerMah;
+
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
+ powerDurationAndTraffic.durationMs);
+ app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
+ powerDurationAndTraffic.powerMah);
+
+ if (app.getUid() == Process.WIFI_UID) {
+ systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
+ app.excludeFromBatteryUsageStats();
+ }
+ }
+
+ calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED,
+ hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
+
+ systemBatteryConsumerBuilder
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
+ powerDurationAndTraffic.durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
+ powerDurationAndTraffic.powerMah);
}
/**
@@ -64,100 +137,151 @@
// batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
// so always check this field.
- mHasWifiPowerReporting = mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
+ final boolean hasWifiPowerReporting =
+ mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
- super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
+ final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
- BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
- calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
-
+ long totalAppDurationMs = 0;
+ double totalAppPowerMah = 0;
+ final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
for (int i = sippers.size() - 1; i >= 0; i--) {
- BatterySipper app = sippers.get(i);
- if (app.getUid() == Process.WIFI_UID) {
- if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
- app.isAggregated = true;
- bs.add(app);
+ final BatterySipper app = sippers.get(i);
+ if (app.drainType == BatterySipper.DrainType.APP) {
+ calculateApp(powerDurationAndTraffic, app.uidObj, rawRealtimeUs, statsType,
+ hasWifiPowerReporting);
+
+ totalAppDurationMs += powerDurationAndTraffic.durationMs;
+ totalAppPowerMah += powerDurationAndTraffic.powerMah;
+
+ app.wifiPowerMah = powerDurationAndTraffic.powerMah;
+ app.wifiRunningTimeMs = powerDurationAndTraffic.durationMs;
+ app.wifiRxBytes = powerDurationAndTraffic.wifiRxBytes;
+ app.wifiRxPackets = powerDurationAndTraffic.wifiRxPackets;
+ app.wifiTxBytes = powerDurationAndTraffic.wifiTxBytes;
+ app.wifiTxPackets = powerDurationAndTraffic.wifiTxPackets;
+ if (app.getUid() == Process.WIFI_UID) {
+ if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
+ app.isAggregated = true;
+ bs.add(app);
+ }
}
}
+
+ calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs, statsType,
+ hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
+
+ bs.wifiRunningTimeMs += powerDurationAndTraffic.durationMs;
+ bs.wifiPowerMah += powerDurationAndTraffic.powerMah;
+
if (bs.sumPower() > 0) {
sippers.add(bs);
}
}
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- if (!mHasWifiPowerReporting) {
- mWifiPowerEstimator.calculateApp(app, u, rawRealtimeUs, rawUptimeUs, statsType);
- return;
- }
-
- final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
- if (counter == null) {
- return;
- }
-
- final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
- final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
- final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
- app.wifiRunningTimeMs = idleTime + rxTime + txTime;
- mTotalAppRunningTime += app.wifiRunningTimeMs;
-
- app.wifiPowerMah =
- ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
- / (1000 * 60 * 60);
- mTotalAppPowerDrain += app.wifiPowerMah;
-
- app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
+ private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic, BatteryStats.Uid u,
+ long rawRealtimeUs,
+ int statsType, boolean hasWifiPowerReporting) {
+ powerDurationAndTraffic.wifiRxPackets = u.getNetworkActivityPackets(
+ BatteryStats.NETWORK_WIFI_RX_DATA,
statsType);
- app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
+ powerDurationAndTraffic.wifiTxPackets = u.getNetworkActivityPackets(
+ BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
- app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
+ powerDurationAndTraffic.wifiRxBytes = u.getNetworkActivityBytes(
+ BatteryStats.NETWORK_WIFI_RX_DATA,
statsType);
- app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
+ powerDurationAndTraffic.wifiTxBytes = u.getNetworkActivityBytes(
+ BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
- if (DEBUG && app.wifiPowerMah != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime + "ms tx=" +
- txTime + "ms power=" + formatCharge(app.wifiPowerMah));
+ if (hasWifiPowerReporting) {
+ final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
+ if (counter != null) {
+ final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
+ final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+ final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
+
+ powerDurationAndTraffic.durationMs = idleTime + rxTime + txTime;
+ powerDurationAndTraffic.powerMah = mIdlePowerEstimator.calculatePower(idleTime)
+ + mTxPowerEstimator.calculatePower(txTime)
+ + mRxPowerEstimator.calculatePower(rxTime);
+
+ if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime
+ + "ms tx=" + txTime + "ms power=" + formatCharge(
+ powerDurationAndTraffic.powerMah));
+ }
+ }
+ } else {
+ final double wifiPacketPower = (
+ powerDurationAndTraffic.wifiRxPackets + powerDurationAndTraffic.wifiTxPackets)
+ * mWifiPowerPerPacket;
+ final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
+ final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
+ long batchScanTimeMs = 0;
+ for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
+ batchScanTimeMs += u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
+ }
+
+ powerDurationAndTraffic.durationMs = wifiRunningTime;
+ powerDurationAndTraffic.powerMah = wifiPacketPower
+ + mPowerOnPowerEstimator.calculatePower(wifiRunningTime)
+ + mScanPowerEstimator.calculatePower(wifiScanTimeMs)
+ + mBatchScanPowerEstimator.calculatePower(batchScanTimeMs);
+
+ if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(
+ powerDurationAndTraffic.powerMah));
+ }
}
}
- private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- if (!mHasWifiPowerReporting) {
- mWifiPowerEstimator.calculateRemaining(app, stats, rawRealtimeUs, rawUptimeUs,
- statsType);
- return;
+ private void calculateRemaining(PowerDurationAndTraffic powerDurationAndTraffic,
+ BatteryStats stats, long rawRealtimeUs,
+ int statsType, boolean hasWifiPowerReporting, long totalAppDurationMs,
+ double totalAppPowerMah) {
+ long totalDurationMs;
+ double totalPowerMah;
+ if (hasWifiPowerReporting) {
+ final BatteryStats.ControllerActivityCounter counter =
+ stats.getWifiControllerActivity();
+
+ final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
+ final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+ final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
+
+ totalDurationMs = idleTimeMs + rxTimeMs + txTimeMs;
+
+ totalPowerMah =
+ counter.getPowerCounter().getCountLocked(statsType) / (double) (1000 * 60 * 60);
+ if (totalPowerMah == 0) {
+ // Some controllers do not report power drain, so we can calculate it here.
+ totalPowerMah = mIdlePowerEstimator.calculatePower(idleTimeMs)
+ + mTxPowerEstimator.calculatePower(txTimeMs)
+ + mRxPowerEstimator.calculatePower(rxTimeMs);
+ }
+ } else {
+ totalDurationMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType) / 1000;
+ totalPowerMah = mPowerOnPowerEstimator.calculatePower(totalDurationMs);
}
- final BatteryStats.ControllerActivityCounter counter = stats.getWifiControllerActivity();
-
- final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
- final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
- final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
-
- app.wifiRunningTimeMs = Math.max(0,
- (idleTimeMs + rxTimeMs + txTimeMs) - mTotalAppRunningTime);
-
- double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
- / (double) (1000 * 60 * 60);
- if (powerDrainMah == 0) {
- // Some controllers do not report power drain, so we can calculate it here.
- powerDrainMah = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
- + (rxTimeMs * mRxCurrentMa)) / (1000 * 60 * 60);
- }
- app.wifiPowerMah = Math.max(0, powerDrainMah - mTotalAppPowerDrain);
+ powerDurationAndTraffic.durationMs = Math.max(0, totalDurationMs - totalAppDurationMs);
+ powerDurationAndTraffic.powerMah = Math.max(0, totalPowerMah - totalAppPowerMah);
if (DEBUG) {
- Log.d(TAG, "left over WiFi power: " + formatCharge(app.wifiPowerMah));
+ Log.d(TAG, "left over WiFi power: " + formatCharge(powerDurationAndTraffic.powerMah));
}
}
- @Override
- public void reset() {
- mTotalAppPowerDrain = 0;
- mTotalAppRunningTime = 0;
- mWifiPowerEstimator.reset();
+ /**
+ * Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
+ */
+ private static double getWifiPowerPerPacket(PowerProfile profile) {
+ // TODO(b/179392913): Extract average bit rates from system
+ final long wifiBps = 1000000;
+ final double averageWifiActivePower =
+ profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE) / 3600;
+ return averageWifiActivePower / (((double) wifiBps) / 8 / 2048);
}
}
diff --git a/core/java/com/android/internal/os/WifiPowerEstimator.java b/core/java/com/android/internal/os/WifiPowerEstimator.java
deleted file mode 100644
index d0a105c..0000000
--- a/core/java/com/android/internal/os/WifiPowerEstimator.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2015 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.os;
-
-import android.os.BatteryStats;
-import android.os.Process;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.List;
-
-/**
- * Estimates WiFi power usage based on timers in BatteryStats.
- */
-public class WifiPowerEstimator extends PowerCalculator {
- private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
- private static final String TAG = "WifiPowerEstimator";
- private final double mWifiPowerPerPacket;
- private final double mWifiPowerOn;
- private final double mWifiPowerScan;
- private final double mWifiPowerBatchScan;
- private long mTotalAppWifiRunningTimeMs = 0;
-
- public WifiPowerEstimator(PowerProfile profile) {
- mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
- mWifiPowerOn = profile.getAveragePower(PowerProfile.POWER_WIFI_ON);
- mWifiPowerScan = profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN);
- mWifiPowerBatchScan = profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN);
- }
-
- @Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
-
- BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
- calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
-
- for (int i = sippers.size() - 1; i >= 0; i--) {
- BatterySipper app = sippers.get(i);
- if (app.getUid() == Process.WIFI_UID) {
- if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
- app.isAggregated = true;
- bs.add(app);
- }
- }
- if (bs.sumPower() > 0) {
- sippers.add(bs);
- }
- }
-
- /**
- * Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
- */
- private static double getWifiPowerPerPacket(PowerProfile profile) {
- final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system
- final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
- / 3600;
- return WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048);
- }
-
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
- statsType);
- app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
- statsType);
- app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
- statsType);
- app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
- statsType);
-
- final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
- * mWifiPowerPerPacket;
-
- app.wifiRunningTimeMs = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
- mTotalAppWifiRunningTimeMs += app.wifiRunningTimeMs;
- final double wifiLockPower = (app.wifiRunningTimeMs * mWifiPowerOn) / (1000*60*60);
-
- final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
- final double wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000*60*60);
-
- double wifiBatchScanPower = 0;
- for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
- final long batchScanTimeMs =
- u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
- final double batchScanPower = (batchScanTimeMs * mWifiPowerBatchScan) / (1000*60*60);
- wifiBatchScanPower += batchScanPower;
- }
-
- app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
- if (DEBUG && app.wifiPowerMah != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(app.wifiPowerMah));
- }
- }
-
- void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType)
- / 1000;
- final double powerDrain = ((totalRunningTimeMs - mTotalAppWifiRunningTimeMs) * mWifiPowerOn)
- / (1000*60*60);
- app.wifiRunningTimeMs = totalRunningTimeMs;
- app.wifiPowerMah = Math.max(0, powerDrain);
- }
-
- @Override
- public void reset() {
- mTotalAppWifiRunningTimeMs = 0;
- }
-}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index b99c953..6b1d408 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -18,8 +18,8 @@
import static android.system.OsConstants.O_CLOEXEC;
-import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
-
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.net.Credentials;
import android.net.LocalServerSocket;
@@ -36,17 +36,16 @@
import com.android.internal.net.NetworkUtilsInternal;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
import dalvik.system.ZygoteHooks;
import libcore.io.IoUtils;
-import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileDescriptor;
import java.io.IOException;
-import java.io.InputStreamReader;
/** @hide */
public final class Zygote {
@@ -238,6 +237,8 @@
*/
public static final String CHILD_ZYGOTE_UID_RANGE_END = "--uid-range-end=";
+ private static final String TAG = "Zygote";
+
/** Prefix prepended to socket names created by init */
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
@@ -408,6 +409,10 @@
// Note that this event ends at the end of handleChildProc.
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
+ if (gids != null && gids.length > 0) {
+ NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
+ }
+
// Set the Java Language thread priority to the default value for new apps.
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
@@ -580,114 +585,163 @@
private static native int nativeGetUsapPoolEventFD();
/**
- * Fork a new unspecialized app process from the zygote
+ * Fork a new unspecialized app process from the zygote. Adds the Usap to the native
+ * Usap table.
*
* @param usapPoolSocket The server socket the USAP will call accept on
- * @param sessionSocketRawFDs Anonymous session sockets that are currently open
- * @param isPriorityFork Value controlling the process priority level until accept is called
- * @return In the Zygote process this function will always return null; in unspecialized app
- * processes this function will return a Runnable object representing the new
- * application that is passed up from usapMain.
+ * @param sessionSocketRawFDs Anonymous session sockets that are currently open.
+ * These are closed in the child.
+ * @param isPriorityFork Raise the initial process priority level because this is on the
+ * critical path for application startup.
+ * @return In the child process, this returns a Runnable that waits for specialization
+ * info to start an app process. In the sygote/parent process this returns null.
*/
- static Runnable forkUsap(LocalServerSocket usapPoolSocket,
- int[] sessionSocketRawFDs,
- boolean isPriorityFork) {
- FileDescriptor[] pipeFDs;
+ static @Nullable Runnable forkUsap(LocalServerSocket usapPoolSocket,
+ int[] sessionSocketRawFDs,
+ boolean isPriorityFork) {
+ FileDescriptor readFD;
+ FileDescriptor writeFD;
try {
- pipeFDs = Os.pipe2(O_CLOEXEC);
+ FileDescriptor[] pipeFDs = Os.pipe2(O_CLOEXEC);
+ readFD = pipeFDs[0];
+ writeFD = pipeFDs[1];
} catch (ErrnoException errnoEx) {
throw new IllegalStateException("Unable to create USAP pipe.", errnoEx);
}
- int pid =
- nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(),
- sessionSocketRawFDs, isPriorityFork);
-
+ int pid = nativeForkApp(readFD.getInt$(), writeFD.getInt$(),
+ sessionSocketRawFDs, /*argsKnown=*/ false, isPriorityFork);
if (pid == 0) {
- IoUtils.closeQuietly(pipeFDs[0]);
- return usapMain(usapPoolSocket, pipeFDs[1]);
+ IoUtils.closeQuietly(readFD);
+ return childMain(null, usapPoolSocket, writeFD);
+ } else if (pid == -1) {
+ // Fork failed.
+ return null;
} else {
- // The read-end of the pipe will be closed by the native code.
- // See removeUsapTableEntry();
- IoUtils.closeQuietly(pipeFDs[1]);
+ // readFD will be closed by the native code. See removeUsapTableEntry();
+ IoUtils.closeQuietly(writeFD);
+ nativeAddUsapTableEntry(pid, readFD.getInt$());
return null;
}
}
- private static native int nativeForkUsap(int readPipeFD,
- int writePipeFD,
- int[] sessionSocketRawFDs,
- boolean isPriorityFork);
+ private static native int nativeForkApp(int readPipeFD,
+ int writePipeFD,
+ int[] sessionSocketRawFDs,
+ boolean argsKnown,
+ boolean isPriorityFork);
/**
- * This function is used by unspecialized app processes to wait for specialization requests from
- * the system server.
+ * Add an entry for a new Usap to the table maintained in native code.
+ */
+ @CriticalNative
+ private static native void nativeAddUsapTableEntry(int pid, int readPipeFD);
+
+ /**
+ * Fork a new app process from the zygote. argBuffer contains a fork command that
+ * request neither a child zygote, nor a wrapped process. Continue to accept connections
+ * on the specified socket, use those to refill argBuffer, and continue to process
+ * sufficiently simple fork requests. We presume that the only open file descriptors
+ * requiring special treatment are the session socket embedded in argBuffer, and
+ * zygoteSocket.
+ * @param argBuffer containing initial command and the connected socket from which to
+ * read more
+ * @param zygoteSocket socket from which to obtain new connections when current argBuffer
+ * one is disconnected
+ * @param expectedUId Uid of peer for initial requests. Subsequent requests from a different
+ * peer will cause us to return rather than perform the requested fork.
+ * @param minUid Minimum Uid enforced for all but first fork request. The caller checks
+ * the Uid policy for the initial request.
+ * @param firstNiceName name of first created process. Used for error reporting only.
+ * @return A Runnable in each child process, null in the parent.
+ * If this returns in then argBuffer still contains a command needing to be executed.
+ */
+ static @Nullable Runnable forkSimpleApps(@NonNull ZygoteCommandBuffer argBuffer,
+ @NonNull FileDescriptor zygoteSocket,
+ int expectedUid,
+ int minUid,
+ @Nullable String firstNiceName) {
+ boolean in_child =
+ argBuffer.forkRepeatedly(zygoteSocket, expectedUid, minUid, firstNiceName);
+ if (in_child) {
+ return childMain(argBuffer, /*usapPoolSocket=*/null, /*writePipe=*/null);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Specialize the current process into one described by argBuffer or the command read from
+ * usapPoolSocket. Exactly one of those must be null. If we are given an argBuffer, we close
+ * it. Used both for a specializing a USAP process, and for process creation without USAPs.
+ * In both cases, we specialize the process after first returning to Java code.
*
* @param writePipe The write end of the reporting pipe used to communicate with the poll loop
* of the ZygoteServer.
* @return A runnable oject representing the new application.
*/
- private static Runnable usapMain(LocalServerSocket usapPoolSocket,
- FileDescriptor writePipe) {
+ private static Runnable childMain(@Nullable ZygoteCommandBuffer argBuffer,
+ @Nullable LocalServerSocket usapPoolSocket,
+ FileDescriptor writePipe) {
final int pid = Process.myPid();
- Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
- LocalSocket sessionSocket = null;
DataOutputStream usapOutputStream = null;
- Credentials peerCredentials = null;
ZygoteArguments args = null;
- // Change the priority to max before calling accept so we can respond to new specialization
- // requests as quickly as possible. This will be reverted to the default priority in the
- // native specialization code.
- boostUsapPriority();
+ // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
+ blockSigTerm();
- while (true) {
- try {
- sessionSocket = usapPoolSocket.accept();
+ LocalSocket sessionSocket = null;
+ if (argBuffer == null) {
+ // Read arguments from usapPoolSocket instead.
- // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
- blockSigTerm();
+ Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
- BufferedReader usapReader =
- new BufferedReader(new InputStreamReader(sessionSocket.getInputStream()));
- usapOutputStream =
- new DataOutputStream(sessionSocket.getOutputStream());
+ // Change the priority to max before calling accept so we can respond to new
+ // specialization requests as quickly as possible. This will be reverted to the
+ // default priority in the native specialization code.
+ boostUsapPriority();
- peerCredentials = sessionSocket.getPeerCredentials();
+ while (true) {
+ ZygoteCommandBuffer tmpArgBuffer = null;
+ try {
+ sessionSocket = usapPoolSocket.accept();
- String[] argStrings = readArgumentList(usapReader);
-
- if (argStrings != null) {
- args = new ZygoteArguments(argStrings);
-
+ usapOutputStream =
+ new DataOutputStream(sessionSocket.getOutputStream());
+ Credentials peerCredentials = sessionSocket.getPeerCredentials();
+ tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket);
+ args = ZygoteArguments.getInstance(argBuffer);
+ applyUidSecurityPolicy(args, peerCredentials);
// TODO (chriswailes): Should this only be run for debug builds?
validateUsapCommand(args);
break;
- } else {
- Log.e("USAP", "Truncated command received.");
- IoUtils.closeQuietly(sessionSocket);
-
- // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary.
- unblockSigTerm();
+ } catch (Exception ex) {
+ Log.e("USAP", ex.getMessage());
}
- } catch (Exception ex) {
- Log.e("USAP", ex.getMessage());
- IoUtils.closeQuietly(sessionSocket);
-
// Re-enable SIGTERM so the USAP can be flushed from the pool if necessary.
unblockSigTerm();
+ IoUtils.closeQuietly(sessionSocket);
+ IoUtils.closeQuietly(tmpArgBuffer);
+ blockSigTerm();
}
+ } else {
+ try {
+ args = ZygoteArguments.getInstance(argBuffer);
+ } catch (Exception ex) {
+ Log.e("AppStartup", ex.getMessage());
+ throw new AssertionError("Failed to parse application start command", ex);
+ }
+ // peerCredentials were checked in parent.
}
-
+ if (args == null) {
+ throw new AssertionError("Empty command line");
+ }
try {
- // SIGTERM is blocked on loop exit. This prevents a USAP that is specializing from
- // being killed during a pool flush.
+ // SIGTERM is blocked here. This prevents a USAP that is specializing from being
+ // killed during a pool flush.
- setAppProcessName(args, "USAP");
-
- applyUidSecurityPolicy(args, peerCredentials);
applyDebuggerSystemProperty(args);
int[][] rlimits = null;
@@ -696,53 +750,57 @@
rlimits = args.mRLimits.toArray(INT_ARRAY_2D);
}
- // This must happen before the SELinux policy for this process is
- // changed when specializing.
- try {
- // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
- // Process.ProcessStartResult object.
- usapOutputStream.writeInt(pid);
- } catch (IOException ioEx) {
- Log.e("USAP", "Failed to write response to session socket: "
- + ioEx.getMessage());
- throw new RuntimeException(ioEx);
- } finally {
- IoUtils.closeQuietly(sessionSocket);
-
+ if (argBuffer == null) {
+ // This must happen before the SELinux policy for this process is
+ // changed when specializing.
try {
- // This socket is closed using Os.close due to an issue with the implementation
- // of LocalSocketImp.close(). Because the raw FD is created by init and then
- // loaded from an environment variable (as opposed to being created by the
- // LocalSocketImpl itself) the current implementation will not actually close
- // the underlying FD.
- //
- // See b/130309968 for discussion of this issue.
- Os.close(usapPoolSocket.getFileDescriptor());
- } catch (ErrnoException ex) {
- Log.e("USAP", "Failed to close USAP pool socket");
- throw new RuntimeException(ex);
+ // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
+ // Process.ProcessStartResult object.
+ usapOutputStream.writeInt(pid);
+ } catch (IOException ioEx) {
+ Log.e("USAP", "Failed to write response to session socket: "
+ + ioEx.getMessage());
+ throw new RuntimeException(ioEx);
+ } finally {
+ try {
+ // Since the raw FD is created by init and then loaded from an environment
+ // variable (as opposed to being created by the LocalSocketImpl itself),
+ // the LocalSocket/LocalSocketImpl does not own the Os-level socket. See
+ // the spec for LocalSocket.createConnectedLocalSocket(FileDescriptor fd).
+ // Thus closing the LocalSocket does not suffice. See b/130309968 for more
+ // discussion.
+ FileDescriptor fd = usapPoolSocket.getFileDescriptor();
+ usapPoolSocket.close();
+ Os.close(fd);
+ } catch (ErrnoException | IOException ex) {
+ Log.e("USAP", "Failed to close USAP pool socket");
+ throw new RuntimeException(ex);
+ }
}
}
- try {
- ByteArrayOutputStream buffer =
- new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES);
- DataOutputStream outputStream = new DataOutputStream(buffer);
+ if (writePipe != null) {
+ try {
+ ByteArrayOutputStream buffer =
+ new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES);
+ DataOutputStream outputStream = new DataOutputStream(buffer);
- // This is written as a long so that the USAP reporting pipe and USAP pool event FD
- // handlers in ZygoteServer.runSelectLoop can be unified. These two cases should
- // both send/receive 8 bytes.
- outputStream.writeLong(pid);
- outputStream.flush();
-
- Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
- } catch (Exception ex) {
- Log.e("USAP",
- String.format("Failed to write PID (%d) to pipe (%d): %s",
- pid, writePipe.getInt$(), ex.getMessage()));
- throw new RuntimeException(ex);
- } finally {
- IoUtils.closeQuietly(writePipe);
+ // This is written as a long so that the USAP reporting pipe and USAP pool
+ // event FD handlers in ZygoteServer.runSelectLoop can be unified. These two
+ // cases should both send/receive 8 bytes.
+ // TODO: Needs tweaking to handle the non-Usap invoke-with case, which expects
+ // a different format.
+ outputStream.writeLong(pid);
+ outputStream.flush();
+ Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
+ } catch (Exception ex) {
+ Log.e("USAP",
+ String.format("Failed to write PID (%d) to pipe (%d): %s",
+ pid, writePipe.getInt$(), ex.getMessage()));
+ throw new RuntimeException(ex);
+ } finally {
+ IoUtils.closeQuietly(writePipe);
+ }
}
specializeAppProcess(args.mUid, args.mGid, args.mGids,
@@ -849,13 +907,29 @@
return nativeRemoveUsapTableEntry(usapPID);
}
+ @CriticalNative
private static native boolean nativeRemoveUsapTableEntry(int usapPID);
/**
- * uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal
+ * Return the minimum child uid that the given peer is allowed to create.
+ * uid 1000 (Process.SYSTEM_UID) may specify any uid ≥ 1000 in normal
* operation. It may also specify any gid and setgroups() list it chooses.
* In factory test mode, it may specify any UID.
- *
+ */
+ static int minChildUid(Credentials peer) {
+ if (peer.getUid() == Process.SYSTEM_UID
+ && FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF) {
+ /* In normal operation, SYSTEM_UID can only specify a restricted
+ * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
+ */
+ return Process.SYSTEM_UID;
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * Adjust uid and gid arguments, ensuring that the security policy is satisfied.
* @param args non-null; zygote spawner arguments
* @param peer non-null; peer credentials
* @throws ZygoteSecurityException Indicates a security issue when applying the UID based
@@ -864,17 +938,10 @@
static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)
throws ZygoteSecurityException {
- if (peer.getUid() == Process.SYSTEM_UID) {
- /* In normal operation, SYSTEM_UID can only specify a restricted
- * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
- */
- boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
-
- if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) {
- throw new ZygoteSecurityException(
- "System UID may not launch process with UID < "
- + Process.SYSTEM_UID);
- }
+ if (args.mUidSpecified && (args.mUid < minChildUid(peer))) {
+ throw new ZygoteSecurityException(
+ "System UID may not launch process with UID < "
+ + Process.SYSTEM_UID);
}
// If not otherwise specified, uid and gid are inherited from peer
@@ -960,45 +1027,6 @@
}
/**
- * Reads an argument list from the provided socket
- * @return Argument list or null if EOF is reached
- * @throws IOException passed straight through
- */
- static String[] readArgumentList(BufferedReader socketReader) throws IOException {
- int argc;
-
- try {
- String argc_string = socketReader.readLine();
-
- if (argc_string == null) {
- // EOF reached.
- return null;
- }
- argc = Integer.parseInt(argc_string);
-
- } catch (NumberFormatException ex) {
- Log.e("Zygote", "Invalid Zygote wire format: non-int at argc");
- throw new IOException("Invalid wire format");
- }
-
- // See bug 1092107: large argc can be used for a DOS attack
- if (argc > MAX_ZYGOTE_ARGC) {
- throw new IOException("Max arg count exceeded");
- }
-
- String[] args = new String[argc];
- for (int arg_index = 0; arg_index < argc; arg_index++) {
- args[arg_index] = socketReader.readLine();
- if (args[arg_index] == null) {
- // We got an unexpected EOF.
- throw new IOException("Truncated request");
- }
- }
-
- return args;
- }
-
- /**
* Creates a managed LocalServerSocket object using a file descriptor
* created by an init.rc script. The init scripts that specify the
* sockets name can be found in system/core/rootdir. The socket is bound
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 32b808a..65b454d 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -16,8 +16,8 @@
package com.android.internal.os;
+import java.io.EOFException;
import java.util.ArrayList;
-import java.util.Arrays;
/**
* Handles argument parsing for args related to the zygote spawner.
@@ -245,20 +245,34 @@
/**
* Constructs instance and parses args
*
- * @param args zygote command-line args
+ * @param args zygote command-line args as ZygoteCommandBuffer, positioned after argument count.
*/
- ZygoteArguments(String[] args) throws IllegalArgumentException {
- parseArgs(args);
+ private ZygoteArguments(ZygoteCommandBuffer args, int argCount)
+ throws IllegalArgumentException, EOFException {
+ parseArgs(args, argCount);
+ }
+
+ /**
+ * Return a new ZygoteArguments reflecting the contents of the given ZygoteCommandBuffer. Return
+ * null if the ZygoteCommandBuffer was positioned at EOF. Assumes the buffer is initially
+ * positioned at the beginning of the command.
+ */
+ public static ZygoteArguments getInstance(ZygoteCommandBuffer args)
+ throws IllegalArgumentException, EOFException {
+ int argCount = args.getCount();
+ return argCount == 0 ? null : new ZygoteArguments(args, argCount);
}
/**
* Parses the commandline arguments intended for the Zygote spawner (such as "--setuid=" and
- * "--setgid=") and creates an array containing the remaining args.
+ * "--setgid=") and creates an array containing the remaining args. Return false if we were
+ * at EOF.
*
* Per security review bug #1112214, duplicate args are disallowed in critical cases to make
* injection harder.
*/
- private void parseArgs(String[] args) throws IllegalArgumentException {
+ private void parseArgs(ZygoteCommandBuffer args, int argCount)
+ throws IllegalArgumentException, EOFException {
/*
* See android.os.ZygoteProcess.zygoteSendArgsAndGetResult()
* Presently the wire format to the zygote process is:
@@ -269,13 +283,13 @@
* the child or -1 on failure.
*/
- int curArg = 0;
-
+ String unprocessedArg = null;
+ int curArg = 0; // Index of arg
boolean seenRuntimeArgs = false;
-
boolean expectRuntimeArgs = true;
- for ( /* curArg */ ; curArg < args.length; curArg++) {
- String arg = args[curArg];
+
+ for ( /* curArg */ ; curArg < argCount; ++curArg) {
+ String arg = args.nextArg();
if (arg.equals("--")) {
curArg++;
@@ -367,7 +381,8 @@
"Duplicate arg specified");
}
try {
- mInvokeWith = args[++curArg];
+ ++curArg;
+ mInvokeWith = args.nextArg();
} catch (IndexOutOfBoundsException ex) {
throw new IllegalArgumentException(
"--invoke-with requires argument");
@@ -397,12 +412,14 @@
} else if (arg.startsWith("--app-data-dir=")) {
mAppDataDir = getAssignmentValue(arg);
} else if (arg.equals("--preload-app")) {
- mPreloadApp = args[++curArg];
+ ++curArg;
+ mPreloadApp = args.nextArg();
} else if (arg.equals("--preload-package")) {
- mPreloadPackage = args[++curArg];
- mPreloadPackageLibs = args[++curArg];
- mPreloadPackageLibFileName = args[++curArg];
- mPreloadPackageCacheKey = args[++curArg];
+ curArg += 4;
+ mPreloadPackage = args.nextArg();
+ mPreloadPackageLibs = args.nextArg();
+ mPreloadPackageLibFileName = args.nextArg();
+ mPreloadPackageCacheKey = args.nextArg();
} else if (arg.equals("--preload-default")) {
mPreloadDefault = true;
expectRuntimeArgs = false;
@@ -411,8 +428,11 @@
} else if (arg.equals("--set-api-denylist-exemptions")) {
// consume all remaining args; this is a stand-alone command, never included
// with the regular fork command.
- mApiDenylistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
- curArg = args.length;
+ mApiDenylistExemptions = new String[argCount - curArg - 1];
+ ++curArg;
+ for (int i = 0; curArg < argCount; ++curArg, ++i) {
+ mApiDenylistExemptions[i] = args.nextArg();
+ }
expectRuntimeArgs = false;
} else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
String rateStr = getAssignmentValue(arg);
@@ -462,35 +482,46 @@
} else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
mBindMountAppDataDirs = true;
} else {
+ unprocessedArg = arg;
break;
}
}
+ // curArg is the index of the first unprocessed argument. That argument is either referenced
+ // by unprocessedArg or not read yet.
if (mBootCompleted) {
- if (args.length - curArg > 0) {
+ if (argCount > curArg) {
throw new IllegalArgumentException("Unexpected arguments after --boot-completed");
}
} else if (mAbiListQuery || mPidQuery) {
- if (args.length - curArg > 0) {
+ if (argCount > curArg) {
throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
}
} else if (mPreloadPackage != null) {
- if (args.length - curArg > 0) {
+ if (argCount > curArg) {
throw new IllegalArgumentException(
"Unexpected arguments after --preload-package.");
}
} else if (mPreloadApp != null) {
- if (args.length - curArg > 0) {
+ if (argCount > curArg) {
throw new IllegalArgumentException(
"Unexpected arguments after --preload-app.");
}
} else if (expectRuntimeArgs) {
if (!seenRuntimeArgs) {
- throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+ throw new IllegalArgumentException("Unexpected argument : "
+ + (unprocessedArg == null ? args.nextArg() : unprocessedArg));
}
- mRemainingArgs = new String[args.length - curArg];
- System.arraycopy(args, curArg, mRemainingArgs, 0, mRemainingArgs.length);
+ mRemainingArgs = new String[argCount - curArg];
+ int i = 0;
+ if (unprocessedArg != null) {
+ mRemainingArgs[0] = unprocessedArg;
+ ++i;
+ }
+ for (; i < argCount - curArg; ++i) {
+ mRemainingArgs[i] = args.nextArg();
+ }
}
if (mStartChildZygote) {
diff --git a/core/java/com/android/internal/os/ZygoteCommandBuffer.java b/core/java/com/android/internal/os/ZygoteCommandBuffer.java
new file mode 100644
index 0000000..b61ae7a
--- /dev/null
+++ b/core/java/com/android/internal/os/ZygoteCommandBuffer.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.LocalSocket;
+
+import java.io.FileDescriptor;
+import java.lang.ref.Reference; // For reachabilityFence.
+
+/**
+ * A native-accessible buffer for Zygote commands. Designed to support repeated forking
+ * of applications without intervening memory allocation, thus keeping zygote memory
+ * as stable as possible.
+ * A ZygoteCommandBuffer may have an associated socket from which it can be refilled.
+ * Otherwise the contents are explicitly set by getInstance().
+ *
+ * NOT THREAD-SAFE. No methods may be called concurrently from multiple threads.
+ *
+ * Only one ZygoteCommandBuffer can exist at a time.
+ * Must be explicitly closed before being dropped.
+ * @hide
+ */
+class ZygoteCommandBuffer implements AutoCloseable {
+ private long mNativeBuffer; // Not final so that we can clear it in close().
+
+ /**
+ * The command socket.
+ *
+ * mSocket is retained in the child process in "peer wait" mode, so
+ * that it closes when the child process terminates. In other cases,
+ * it is closed in the peer.
+ */
+ private final LocalSocket mSocket;
+ private final int mNativeSocket;
+
+ /**
+ * Constructs instance from file descriptor from which the command will be read.
+ * Only a single instance may be live in a given process. The native code checks.
+ *
+ * @param fd file descriptor to read from. The setCommand() method may be used if and only if
+ * fd is null.
+ */
+ ZygoteCommandBuffer(@Nullable LocalSocket socket) {
+ mSocket = socket;
+ if (socket == null) {
+ mNativeSocket = -1;
+ } else {
+ mNativeSocket = mSocket.getFileDescriptor().getInt$();
+ }
+ mNativeBuffer = getNativeBuffer(mNativeSocket);
+ }
+
+ /**
+ * Constructs an instance with explicitly supplied arguments and an invalid
+ * file descriptor. Can only be used for a single command.
+ */
+ ZygoteCommandBuffer(@NonNull String[] args) {
+ this((LocalSocket) null);
+ setCommand(args);
+ }
+
+
+ private static native long getNativeBuffer(int fd);
+
+ /**
+ * Deallocate native resources associated with the one and only command buffer, and prevent
+ * reuse. Subsequent calls to getInstance() will yield a new buffer.
+ * We do not close the associated socket, if any.
+ */
+ @Override
+ public void close() {
+ freeNativeBuffer(mNativeBuffer);
+ mNativeBuffer = 0;
+ }
+
+ private static native void freeNativeBuffer(long /* NativeCommandBuffer* */ nbuffer);
+
+ /**
+ * Read at least the first line of the next command into the buffer, return the argument count
+ * from that line. Assumes we are initially positioned at the beginning of the first line of
+ * the command. Leave the buffer positioned at the beginning of the second command line, i.e.
+ * the first argument. If the buffer has no associated file descriptor, we just reposition to
+ * the beginning of the buffer, and reread existing contents. Returns zero if we started out
+ * at EOF.
+ */
+ int getCount() {
+ try {
+ return nativeGetCount(mNativeBuffer);
+ } finally {
+ // Make sure the mNativeSocket doesn't get closed due to early finalization.
+ Reference.reachabilityFence(mSocket);
+ }
+ }
+
+ private static native int nativeGetCount(long /* NativeCommandBuffer* */ nbuffer);
+
+
+ /*
+ * Set the buffer to contain the supplied sequence of arguments.
+ */
+ private void setCommand(String[] command) {
+ int nArgs = command.length;
+ insert(mNativeBuffer, Integer.toString(nArgs));
+ for (String s: command) {
+ insert(mNativeBuffer, s);
+ }
+ // Native code checks there is no socket; hence no reachabilityFence.
+ }
+
+ private static native void insert(long /* NativeCommandBuffer* */ nbuffer, String s);
+
+ /**
+ * Retrieve the next argument/line from the buffer, filling the buffer as necessary.
+ */
+ String nextArg() {
+ try {
+ return nativeNextArg(mNativeBuffer);
+ } finally {
+ Reference.reachabilityFence(mSocket);
+ }
+ }
+
+ private static native String nativeNextArg(long /* NativeCommandBuffer* */ nbuffer);
+
+ void readFullyAndReset() {
+ try {
+ nativeReadFullyAndReset(mNativeBuffer);
+ } finally {
+ Reference.reachabilityFence(mSocket);
+ }
+ }
+
+ private static native void nativeReadFullyAndReset(long /* NativeCommandBuffer* */ nbuffer);
+
+ /**
+ * Fork a child as specified by the current command in the buffer, and repeat this process
+ * after refilling the buffer, so long as the buffer clearly contains another fork command.
+ *
+ * @param zygoteSocket socket from which to obtain new connections when current one is
+ * disconnected
+ * @param expectedUid Peer UID for current connection. We refuse to deal with requests from
+ * a different UID.
+ * @param minUid the smallest uid that may be request for the child process.
+ * @param firstNiceName The name for the initial process to be forked. Used only for error
+ * reporting.
+ *
+ * @return true in the child, false in the parent. In the parent case, the buffer is positioned
+ * at the beginning of a command that still needs to be processed.
+ */
+ boolean forkRepeatedly(FileDescriptor zygoteSocket, int expectedUid, int minUid,
+ String firstNiceName) {
+ try {
+ return nativeForkRepeatedly(mNativeBuffer, zygoteSocket.getInt$(),
+ expectedUid, minUid, firstNiceName);
+ } finally {
+ Reference.reachabilityFence(mSocket);
+ Reference.reachabilityFence(zygoteSocket);
+ }
+ }
+
+ /*
+ * Repeatedly fork children as above. It commonly does not return in the parent, but it may.
+ * @return true in the chaild, false in the parent if we encounter a command we couldn't handle.
+ */
+ private static native boolean nativeForkRepeatedly(long /* NativeCommandBuffer* */ nbuffer,
+ int zygoteSocketRawFd,
+ int expectedUid,
+ int minUid,
+ String firstNiceName);
+
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 5a576ebb..37c7590 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -36,16 +36,15 @@
import android.util.Log;
import dalvik.system.VMRuntime;
+import dalvik.system.ZygoteHooks;
import libcore.io.IoUtils;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileDescriptor;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.concurrent.TimeUnit;
@@ -67,7 +66,6 @@
private final LocalSocket mSocket;
@UnsupportedAppUsage
private final DataOutputStream mSocketOutStream;
- private final BufferedReader mSocketReader;
@UnsupportedAppUsage
private final Credentials peer;
private final String abiList;
@@ -85,9 +83,6 @@
this.abiList = abiList;
mSocketOutStream = new DataOutputStream(socket.getOutputStream());
- mSocketReader =
- new BufferedReader(
- new InputStreamReader(socket.getInputStream()), Zygote.SOCKET_BUFFER_SIZE);
mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
@@ -111,178 +106,216 @@
}
/**
- * Reads one start command from the command socket. If successful, a child is forked and a
+ * Reads a command from the command socket. If a child is successfully forked, a
* {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
* process. {@code null} is always returned in the parent process (the zygote).
+ * If multipleOK is set, we may keep processing additional fork commands before returning.
*
* If the client closes the socket, an {@code EOF} condition is set, which callers can test
* for by calling {@code ZygoteConnection.isClosedByPeer}.
*/
- Runnable processOneCommand(ZygoteServer zygoteServer) {
- String[] args;
+ Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
+ ZygoteArguments parsedArgs;
- try {
- args = Zygote.readArgumentList(mSocketReader);
- } catch (IOException ex) {
- throw new IllegalStateException("IOException on command socket", ex);
+ try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
+ while (true) {
+ try {
+ parsedArgs = ZygoteArguments.getInstance(argBuffer);
+ // Keep argBuffer around, since we need it to fork.
+ } catch (IOException ex) {
+ throw new IllegalStateException("IOException on command socket", ex);
+ }
+ if (parsedArgs == null) {
+ isEof = true;
+ return null;
+ }
+
+ int pid;
+ FileDescriptor childPipeFd = null;
+ FileDescriptor serverPipeFd = null;
+
+ if (parsedArgs.mBootCompleted) {
+ handleBootCompleted();
+ return null;
+ }
+
+ if (parsedArgs.mAbiListQuery) {
+ handleAbiListQuery();
+ return null;
+ }
+
+ if (parsedArgs.mPidQuery) {
+ handlePidQuery();
+ return null;
+ }
+
+ if (parsedArgs.mUsapPoolStatusSpecified) {
+ // Handle this once we've released the argBuffer, to avoid opening a second one.
+ break;
+ }
+
+ if (parsedArgs.mPreloadDefault) {
+ handlePreload();
+ return null;
+ }
+
+ if (parsedArgs.mPreloadPackage != null) {
+ handlePreloadPackage(parsedArgs.mPreloadPackage,
+ parsedArgs.mPreloadPackageLibs,
+ parsedArgs.mPreloadPackageLibFileName,
+ parsedArgs.mPreloadPackageCacheKey);
+ return null;
+ }
+
+ if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
+ byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
+ Parcel appInfoParcel = Parcel.obtain();
+ appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
+ appInfoParcel.setDataPosition(0);
+ ApplicationInfo appInfo =
+ ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
+ appInfoParcel.recycle();
+ if (appInfo != null) {
+ handlePreloadApp(appInfo);
+ } else {
+ throw new IllegalArgumentException("Failed to deserialize --preload-app");
+ }
+ return null;
+ }
+
+ if (parsedArgs.mApiDenylistExemptions != null) {
+ return handleApiDenylistExemptions(zygoteServer,
+ parsedArgs.mApiDenylistExemptions);
+ }
+
+ if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
+ || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
+ return handleHiddenApiAccessLogSampleRate(zygoteServer,
+ parsedArgs.mHiddenApiAccessLogSampleRate,
+ parsedArgs.mHiddenApiAccessStatslogSampleRate);
+ }
+
+ if (parsedArgs.mPermittedCapabilities != 0
+ || parsedArgs.mEffectiveCapabilities != 0) {
+ throw new ZygoteSecurityException("Client may not specify capabilities: "
+ + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
+ + ", effective=0x"
+ + Long.toHexString(parsedArgs.mEffectiveCapabilities));
+ }
+
+ Zygote.applyUidSecurityPolicy(parsedArgs, peer);
+ Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
+
+ Zygote.applyDebuggerSystemProperty(parsedArgs);
+ Zygote.applyInvokeWithSystemProperty(parsedArgs);
+
+ int[][] rlimits = null;
+
+ if (parsedArgs.mRLimits != null) {
+ rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
+ }
+
+ int[] fdsToIgnore = null;
+
+ if (parsedArgs.mInvokeWith != null) {
+ try {
+ FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
+ childPipeFd = pipeFds[1];
+ serverPipeFd = pipeFds[0];
+ Os.fcntlInt(childPipeFd, F_SETFD, 0);
+ fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
+ } catch (ErrnoException errnoEx) {
+ throw new IllegalStateException("Unable to set up pipe for invoke-with",
+ errnoEx);
+ }
+ }
+
+ /*
+ * In order to avoid leaking descriptors to the Zygote child,
+ * the native code must close the two Zygote socket descriptors
+ * in the child process before it switches from Zygote-root to
+ * the UID and privileges of the application being launched.
+ *
+ * In order to avoid "bad file descriptor" errors when the
+ * two LocalSocket objects are closed, the Posix file
+ * descriptors are released via a dup2() call which closes
+ * the socket and substitutes an open descriptor to /dev/null.
+ */
+
+ int [] fdsToClose = { -1, -1 };
+
+ FileDescriptor fd = mSocket.getFileDescriptor();
+
+ if (fd != null) {
+ fdsToClose[0] = fd.getInt$();
+ }
+
+ FileDescriptor zygoteFd = zygoteServer.getZygoteSocketFileDescriptor();
+
+ if (zygoteFd != null) {
+ fdsToClose[1] = zygoteFd.getInt$();
+ }
+
+ if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
+ || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
+ // Continue using old code for now. TODO: Handle these cases in the other path.
+ pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
+ parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
+ parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
+ fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
+ parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
+ parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
+ parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
+ parsedArgs.mBindMountAppStorageDirs);
+
+ try {
+ if (pid == 0) {
+ // in child
+ zygoteServer.setForkChild();
+
+ zygoteServer.closeServerSocket();
+ IoUtils.closeQuietly(serverPipeFd);
+ serverPipeFd = null;
+
+ return handleChildProc(parsedArgs, childPipeFd,
+ parsedArgs.mStartChildZygote);
+ } else {
+ // In the parent. A pid < 0 indicates a failure and will be handled in
+ // handleParentProc.
+ IoUtils.closeQuietly(childPipeFd);
+ childPipeFd = null;
+ handleParentProc(pid, serverPipeFd);
+ return null;
+ }
+ } finally {
+ IoUtils.closeQuietly(childPipeFd);
+ IoUtils.closeQuietly(serverPipeFd);
+ }
+ } else {
+ ZygoteHooks.preFork();
+ Runnable result = Zygote.forkSimpleApps(argBuffer,
+ zygoteServer.getZygoteSocketFileDescriptor(),
+ peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
+ if (result == null) {
+ // parent; we finished some number of forks. Result is Boolean.
+ // We already did the equivalent of handleParentProc().
+ ZygoteHooks.postForkCommon();
+ // argBuffer contains a command not understood by forksimpleApps.
+ continue;
+ } else {
+ // child; result is a Runnable.
+ zygoteServer.setForkChild();
+ Zygote.setAppProcessName(parsedArgs, TAG); // ??? Necessary?
+ return result;
+ }
+ }
+ }
}
-
- // readArgumentList returns null only when it has reached EOF with no available
- // data to read. This will only happen when the remote socket has disconnected.
- if (args == null) {
- isEof = true;
- return null;
- }
-
- int pid;
- FileDescriptor childPipeFd = null;
- FileDescriptor serverPipeFd = null;
-
- ZygoteArguments parsedArgs = new ZygoteArguments(args);
-
- if (parsedArgs.mBootCompleted) {
- handleBootCompleted();
- return null;
- }
-
- if (parsedArgs.mAbiListQuery) {
- handleAbiListQuery();
- return null;
- }
-
- if (parsedArgs.mPidQuery) {
- handlePidQuery();
- return null;
- }
-
if (parsedArgs.mUsapPoolStatusSpecified) {
+ // Now that we've released argBuffer:
return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
}
-
- if (parsedArgs.mPreloadDefault) {
- handlePreload();
- return null;
- }
-
- if (parsedArgs.mPreloadPackage != null) {
- handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
- parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
- return null;
- }
-
- if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
- byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
- Parcel appInfoParcel = Parcel.obtain();
- appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
- appInfoParcel.setDataPosition(0);
- ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
- appInfoParcel.recycle();
- if (appInfo != null) {
- handlePreloadApp(appInfo);
- } else {
- throw new IllegalArgumentException("Failed to deserialize --preload-app");
- }
- return null;
- }
-
- if (parsedArgs.mApiDenylistExemptions != null) {
- return handleApiDenylistExemptions(zygoteServer, parsedArgs.mApiDenylistExemptions);
- }
-
- if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
- || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
- return handleHiddenApiAccessLogSampleRate(zygoteServer,
- parsedArgs.mHiddenApiAccessLogSampleRate,
- parsedArgs.mHiddenApiAccessStatslogSampleRate);
- }
-
- if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
- throw new ZygoteSecurityException("Client may not specify capabilities: "
- + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
- + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
- }
-
- Zygote.applyUidSecurityPolicy(parsedArgs, peer);
- Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
-
- Zygote.applyDebuggerSystemProperty(parsedArgs);
- Zygote.applyInvokeWithSystemProperty(parsedArgs);
-
- int[][] rlimits = null;
-
- if (parsedArgs.mRLimits != null) {
- rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
- }
-
- int[] fdsToIgnore = null;
-
- if (parsedArgs.mInvokeWith != null) {
- try {
- FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
- childPipeFd = pipeFds[1];
- serverPipeFd = pipeFds[0];
- Os.fcntlInt(childPipeFd, F_SETFD, 0);
- fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
- } catch (ErrnoException errnoEx) {
- throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
- }
- }
-
- /*
- * In order to avoid leaking descriptors to the Zygote child,
- * the native code must close the two Zygote socket descriptors
- * in the child process before it switches from Zygote-root to
- * the UID and privileges of the application being launched.
- *
- * In order to avoid "bad file descriptor" errors when the
- * two LocalSocket objects are closed, the Posix file
- * descriptors are released via a dup2() call which closes
- * the socket and substitutes an open descriptor to /dev/null.
- */
-
- int [] fdsToClose = { -1, -1 };
-
- FileDescriptor fd = mSocket.getFileDescriptor();
-
- if (fd != null) {
- fdsToClose[0] = fd.getInt$();
- }
-
- fd = zygoteServer.getZygoteSocketFileDescriptor();
-
- if (fd != null) {
- fdsToClose[1] = fd.getInt$();
- }
-
- pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
- parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
- parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
- parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
- parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList,
- parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
-
- try {
- if (pid == 0) {
- // in child
- zygoteServer.setForkChild();
-
- zygoteServer.closeServerSocket();
- IoUtils.closeQuietly(serverPipeFd);
- serverPipeFd = null;
-
- return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
- } else {
- // In the parent. A pid < 0 indicates a failure and will be handled in
- // handleParentProc.
- IoUtils.closeQuietly(childPipeFd);
- childPipeFd = null;
- handleParentProc(pid, serverPipeFd);
- return null;
- }
- } finally {
- IoUtils.closeQuietly(childPipeFd);
- IoUtils.closeQuietly(serverPipeFd);
- }
+ throw new AssertionError("Shouldn't get here");
}
private void handleAbiListQuery() {
@@ -557,7 +590,7 @@
if (res > 0) {
if ((fds[0].revents & POLLIN) != 0) {
- // Only read one byte, so as not to block.
+ // Only read one byte, so as not to block. Really needed?
int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
if (readBytes < 0) {
throw new RuntimeException("Some error");
diff --git a/core/java/com/android/internal/os/ZygoteConnectionConstants.java b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
index 506e39f..0c1cd6d 100644
--- a/core/java/com/android/internal/os/ZygoteConnectionConstants.java
+++ b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
@@ -31,9 +31,6 @@
*/
public static final int CONNECTION_TIMEOUT_MILLIS = 1000;
- /** max number of arguments that a connection can specify */
- public static final int MAX_ZYGOTE_ARGC = 1024;
-
/**
* Wait time for a wrapped app to report back its pid.
*
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index f2ed50e..d5b778e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -65,6 +65,7 @@
import libcore.io.IoUtils;
import java.io.BufferedReader;
+import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -782,7 +783,13 @@
int pid;
try {
- parsedArgs = new ZygoteArguments(args);
+ ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
+ try {
+ parsedArgs = ZygoteArguments.getInstance(commandBuffer);
+ } catch (EOFException e) {
+ throw new AssertionError("Unexpected argument error for forking system server", e);
+ }
+ commandBuffer.close();
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
@@ -861,7 +868,7 @@
* into new processes are required to either set the priority to the default value or terminate
* before executing any non-system code. The native side of this occurs in SpecializeCommon,
* while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
- * ZygoteConnection.handleChildProc, and Zygote.usapMain.
+ * ZygoteConnection.handleChildProc, and Zygote.childMain.
*
* @param argv Command line arguments used to specify the Zygote's configuration.
*/
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 585ddf6..f71b314 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -337,7 +337,7 @@
* @param sessionSocketRawFDs Anonymous session sockets that are currently open
* @return In the Zygote process this function will always return null; in unspecialized app
* processes this function will return a Runnable object representing the new
- * application that is passed up from usapMain.
+ * application that is passed up from childMain (the usap's main wait loop).
*/
Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) {
@@ -420,6 +420,7 @@
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
+ * @param abiList list of ABIs supported by this zygote.
*/
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
@@ -537,22 +538,23 @@
if (pollIndex == 0) {
// Zygote server socket
-
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
-
} else if (pollIndex < usapPoolEventFDIndex) {
// Session socket accepted from the Zygote server socket
try {
ZygoteConnection connection = peers.get(pollIndex);
- final Runnable command = connection.processOneCommand(this);
+ boolean multipleForksOK = !isUsapPoolEnabled()
+ && ZygoteHooks.indefiniteThreadSuspensionOK();
+ final Runnable command =
+ connection.processCommand(this, multipleForksOK);
// TODO (chriswailes): Is this extra check necessary?
if (mIsForkChild) {
// We're in the child. We should always have a command to run at
- // this stage if processOneCommand hasn't called "exec".
+ // this stage if processCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
@@ -565,7 +567,7 @@
}
// We don't know whether the remote side of the socket was closed or
- // not until we attempt to read from it from processOneCommand. This
+ // not until we attempt to read from it from processCommand. This
// shows up as a regular POLLIN event in our regular processing
// loop.
if (connection.isClosedByPeer()) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 9840013..9a91d20 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -124,6 +124,7 @@
import com.android.internal.widget.FloatingToolbar;
import java.util.List;
+import java.util.function.Consumer;
/** @hide */
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
@@ -282,14 +283,19 @@
private final Paint mLegacyNavigationBarBackgroundPaint = new Paint();
private Insets mBackgroundInsets = Insets.NONE;
private Insets mLastBackgroundInsets = Insets.NONE;
- private int mLastBackgroundBlurRadius = 0;
private boolean mDrawLegacyNavigationBarBackground;
private PendingInsetsController mPendingInsetsController = new PendingInsetsController();
+
+ private int mOriginalBackgroundBlurRadius = 0;
+ private int mBackgroundBlurRadius = 0;
+ private int mLastBackgroundBlurRadius = 0;
+ private boolean mCrossWindowBlurEnabled;
private final ViewTreeObserver.OnPreDrawListener mBackgroundBlurOnPreDrawListener = () -> {
- updateBackgroundBlur();
+ updateBackgroundBlurCorners();
return true;
};
+ private Consumer<Boolean> mCrossWindowBlurEnabledListener;
DecorView(Context context, int featureId, PhoneWindow window,
WindowManager.LayoutParams params) {
@@ -1272,23 +1278,17 @@
}
if (mBackgroundInsets.equals(mLastBackgroundInsets)
- && mWindow.mBackgroundBlurRadius == mLastBackgroundBlurRadius
+ && mBackgroundBlurRadius == mLastBackgroundBlurRadius
&& mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) {
return;
}
Drawable destDrawable = mOriginalBackgroundDrawable;
- if (mWindow.mBackgroundBlurRadius > 0 && getViewRootImpl() != null
- && mWindow.isTranslucent()) {
- if (mBackgroundBlurDrawable == null) {
- mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
- }
+ if (mBackgroundBlurRadius > 0) {
destDrawable = new LayerDrawable(new Drawable[] {mBackgroundBlurDrawable,
mOriginalBackgroundDrawable});
- mLastBackgroundBlurRadius = mWindow.mBackgroundBlurRadius;
}
-
if (destDrawable != null && !mBackgroundInsets.equals(Insets.NONE)) {
destDrawable = new InsetDrawable(destDrawable,
mBackgroundInsets.left, mBackgroundInsets.top,
@@ -1309,23 +1309,60 @@
super.setBackgroundDrawable(destDrawable);
mLastBackgroundInsets = mBackgroundInsets;
+ mLastBackgroundBlurRadius = mBackgroundBlurRadius;
mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable;
}
- private void updateBackgroundBlur() {
+ private void updateBackgroundBlurCorners() {
if (mBackgroundBlurDrawable == null) return;
+ float cornerRadius = 0;
// If the blur radius is 0, the blur region won't be sent to surface flinger, so we don't
// need to calculate the corner radius.
- if (mWindow.mBackgroundBlurRadius > 0) {
- if (mOriginalBackgroundDrawable != null) {
- final Outline outline = new Outline();
- mOriginalBackgroundDrawable.getOutline(outline);
- mBackgroundBlurDrawable.setCornerRadius(outline.mMode == Outline.MODE_ROUND_RECT
- ? outline.getRadius() : 0);
- }
+ if (mBackgroundBlurRadius != 0 && mOriginalBackgroundDrawable != null) {
+ final Outline outline = new Outline();
+ mOriginalBackgroundDrawable.getOutline(outline);
+ cornerRadius = outline.mMode == Outline.MODE_ROUND_RECT ? outline.getRadius() : 0;
}
- mBackgroundBlurDrawable.setBlurRadius(mWindow.mBackgroundBlurRadius);
+ mBackgroundBlurDrawable.setCornerRadius(cornerRadius);
+ }
+
+ private void updateBackgroundBlurRadius() {
+ if (getViewRootImpl() == null) return;
+
+ mBackgroundBlurRadius = mCrossWindowBlurEnabled && mWindow.isTranslucent()
+ ? mOriginalBackgroundBlurRadius : 0;
+ if (mBackgroundBlurDrawable == null && mBackgroundBlurRadius > 0) {
+ mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
+ }
+
+ if (mBackgroundBlurDrawable != null) {
+ mBackgroundBlurDrawable.setBlurRadius(mBackgroundBlurRadius);
+ updateBackgroundDrawable();
+ }
+ }
+
+ void setBackgroundBlurRadius(int blurRadius) {
+ mOriginalBackgroundBlurRadius = blurRadius;
+ if (blurRadius > 0) {
+ if (mCrossWindowBlurEnabledListener == null) {
+ mCrossWindowBlurEnabledListener = enabled -> {
+ mCrossWindowBlurEnabled = enabled;
+ updateBackgroundBlurRadius();
+ };
+ getContext().getSystemService(WindowManager.class)
+ .addCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
+ getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+ } else {
+ updateBackgroundBlurRadius();
+ }
+ } else if (mCrossWindowBlurEnabledListener != null) {
+ mCrossWindowBlurEnabledListener = null;
+ getContext().getSystemService(WindowManager.class)
+ .removeCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
+ getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+ updateBackgroundBlurRadius();
+ }
}
@Override
@@ -1758,9 +1795,6 @@
cb.onAttachedToWindow();
}
- getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
- updateBackgroundDrawable();
-
if (mFeatureId == -1) {
/*
* The main window has been attached, try to restore any panels
@@ -1782,6 +1816,9 @@
// renderer about it.
mBackdropFrameRenderer.onConfigurationChange();
}
+
+ updateBackgroundBlurRadius();
+
mWindow.onViewRootImplSet(getViewRootImpl());
}
@@ -1794,8 +1831,6 @@
cb.onDetachedFromWindow();
}
- getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
-
if (mWindow.mDecorContentParent != null) {
mWindow.mDecorContentParent.dismissPopups();
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d06413c..6049486 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -75,6 +75,7 @@
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
+import android.view.CrossWindowBlurListeners;
import android.view.Gravity;
import android.view.IRotationWatcher.Stub;
import android.view.IScrollCaptureCallbacks;
@@ -258,7 +259,7 @@
Drawable mBackgroundDrawable = null;
Drawable mBackgroundFallbackDrawable = null;
- int mBackgroundBlurRadius = 0;
+ private int mBackgroundBlurRadius = 0;
private boolean mLoadElevation = true;
private float mElevation;
@@ -1527,9 +1528,11 @@
@Override
public final void setBackgroundBlurRadius(int blurRadius) {
super.setBackgroundBlurRadius(blurRadius);
- if (getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_CROSS_LAYER_BLUR)) {
- mBackgroundBlurRadius = Math.max(blurRadius, 0);
+ if (CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED) {
+ if (mBackgroundBlurRadius != Math.max(blurRadius, 0)) {
+ mBackgroundBlurRadius = Math.max(blurRadius, 0);
+ mDecor.setBackgroundBlurRadius(mBackgroundBlurRadius);
+ }
}
}
@@ -2556,8 +2559,8 @@
params.flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
}
- params.blurBehindRadius = a.getDimensionPixelSize(
- android.R.styleable.Window_windowBlurBehindRadius, 0);
+ params.setBlurBehindRadius(a.getDimensionPixelSize(
+ android.R.styleable.Window_windowBlurBehindRadius, 0));
}
setBackgroundBlurRadius(a.getDimensionPixelSize(
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index d7b4d78..d49203c 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -193,34 +193,30 @@
return mAccumulatedEnergiesMicroJoules.length;
}
- // TODO: Get rid of the 'accumulate' boolean. It's always true.
/** Updates the given standard energy bucket with the given energy if accumulate is true. */
- public void updateStandardBucket(@StandardEnergyBucket int bucket, long energyDeltaUJ,
- boolean accumulate) {
+ public void updateStandardBucket(@StandardEnergyBucket int bucket, long energyDeltaUJ) {
checkValidStandardBucket(bucket);
- updateEntry(bucket, energyDeltaUJ, accumulate);
+ updateEntry(bucket, energyDeltaUJ);
}
/** Updates the given custom energy bucket with the given energy if accumulate is true. */
- public void updateCustomBucket(int customBucket, long energyDeltaUJ, boolean accumulate) {
+ public void updateCustomBucket(int customBucket, long energyDeltaUJ) {
if (!isValidCustomBucket(customBucket)) {
Slog.e(TAG, "Attempted to update invalid custom bucket " + customBucket);
return;
}
final int index = customBucketToIndex(customBucket);
- updateEntry(index, energyDeltaUJ, accumulate);
+ updateEntry(index, energyDeltaUJ);
}
/** Updates the given index with the given energy if accumulate is true. */
- private void updateEntry(int index, long energyDeltaUJ, boolean accumulate) {
- if (accumulate) {
- if (mAccumulatedEnergiesMicroJoules[index] >= 0L) {
- mAccumulatedEnergiesMicroJoules[index] += energyDeltaUJ;
- } else {
- Slog.wtf(TAG, "Attempting to add " + energyDeltaUJ + " to unavailable bucket "
- + getBucketName(index) + " whose value was "
- + mAccumulatedEnergiesMicroJoules[index]);
- }
+ private void updateEntry(int index, long energyDeltaUJ) {
+ if (mAccumulatedEnergiesMicroJoules[index] >= 0L) {
+ mAccumulatedEnergiesMicroJoules[index] += energyDeltaUJ;
+ } else {
+ Slog.wtf(TAG, "Attempting to add " + energyDeltaUJ + " to unavailable bucket "
+ + getBucketName(index) + " whose value was "
+ + mAccumulatedEnergiesMicroJoules[index]);
}
}
diff --git a/core/java/com/android/internal/power/TEST_MAPPING b/core/java/com/android/internal/power/TEST_MAPPING
new file mode 100644
index 0000000..96f31bc
--- /dev/null
+++ b/core/java/com/android/internal/power/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+ { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+ ]
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+ { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+ { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+ ]
+ }
+ ]
+}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index ef2275d..ab0149f 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -30,6 +30,7 @@
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.PointerIcon;
+import android.view.ScrollCaptureResponse;
import android.view.WindowInsets.Type.InsetsType;
import android.window.ClientWindowFrames;
@@ -160,7 +161,9 @@
@Override
public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
try {
- callbacks.onUnavailable();
+ callbacks.onScrollCaptureResponse(
+ new ScrollCaptureResponse.Builder().setDescription("Not Implemented").build());
+
} catch (RemoteException ex) {
// ignore
}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 8d82e33..c336373 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -35,8 +35,7 @@
* {@hide}
*/
oneway interface IInputMethod {
- void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps,
- int configChanges);
+ void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
in IInlineSuggestionsRequestCallback cb);
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index 85fa791..a41511b 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -16,15 +16,19 @@
package com.android.internal.view;
+import android.annotation.UiThread;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.graphics.HardwareRenderer;
import android.graphics.Matrix;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.RenderNode;
-import android.os.Handler;
+import android.os.CancellationSignal;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.Display.ColorMode;
import android.view.ScrollCaptureCallback;
import android.view.ScrollCaptureSession;
import android.view.Surface;
@@ -44,32 +48,42 @@
* @param <V> the specific View subclass handled
* @see ScrollCaptureViewHelper
*/
+@UiThread
public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCallback {
- public static final long NO_FRAME_PRODUCED = -1;
-
private static final String TAG = "ScrollCaptureViewSupport";
private static final boolean WAIT_FOR_ANIMATION = true;
private final WeakReference<V> mWeakView;
private final ScrollCaptureViewHelper<V> mViewHelper;
- private ViewRenderer mRenderer;
- private Handler mUiHandler;
+ private final ViewRenderer mRenderer;
private boolean mStarted;
private boolean mEnded;
ScrollCaptureViewSupport(V containingView, ScrollCaptureViewHelper<V> viewHelper) {
mWeakView = new WeakReference<>(containingView);
mRenderer = new ViewRenderer();
- mUiHandler = containingView.getHandler();
+ // TODO(b/177649144): provide access to color space from android.media.Image
mViewHelper = viewHelper;
}
- // Base implementation of ScrollCaptureCallback
+ /** Based on ViewRootImpl#updateColorModeIfNeeded */
+ @ColorMode
+ private static int getColorMode(View containingView) {
+ Context context = containingView.getContext();
+ int colorMode = containingView.getViewRootImpl().mWindowAttributes.getColorMode();
+ if (!context.getResources().getConfiguration().isScreenWideColorGamut()) {
+ colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+ }
+ return colorMode;
+ }
@Override
- public final void onScrollCaptureSearch(Consumer<Rect> onReady) {
+ public final void onScrollCaptureSearch(CancellationSignal signal, Consumer<Rect> onReady) {
+ if (signal.isCanceled()) {
+ return;
+ }
V view = mWeakView.get();
mStarted = false;
mEnded = false;
@@ -82,7 +96,11 @@
}
@Override
- public final void onScrollCaptureStart(ScrollCaptureSession session, Runnable onReady) {
+ public final void onScrollCaptureStart(ScrollCaptureSession session, CancellationSignal signal,
+ Runnable onReady) {
+ if (signal.isCanceled()) {
+ return;
+ }
V view = mWeakView.get();
mEnded = false;
@@ -99,18 +117,22 @@
}
@Override
- public final void onScrollCaptureImageRequest(ScrollCaptureSession session, Rect requestRect) {
+ public final void onScrollCaptureImageRequest(ScrollCaptureSession session,
+ CancellationSignal signal, Rect requestRect, Consumer<Rect> onComplete) {
+ if (signal.isCanceled()) {
+ return;
+ }
V view = mWeakView.get();
if (view == null || !view.isVisibleToUser()) {
// Signal to the controller that we have a problem and can't continue.
- session.notifyBufferSent(NO_FRAME_PRODUCED, new Rect());
+ 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()) {
- session.notifyBufferSent(NO_FRAME_PRODUCED, scrollResult.availableArea);
+ onComplete.accept(scrollResult.availableArea);
return;
}
view.invalidate(); // don't wait for vsync
@@ -121,17 +143,13 @@
viewCaptureArea.offset(0, -scrollResult.scrollDelta);
if (WAIT_FOR_ANIMATION) {
- Log.d(TAG, "render: delaying until animation");
view.postOnAnimation(() -> {
- Log.d(TAG, "postOnAnimation(): rendering now");
- long resultFrame = mRenderer.renderView(view, viewCaptureArea);
- Log.d(TAG, "notifyBufferSent: " + scrollResult.availableArea);
-
- session.notifyBufferSent(resultFrame, new Rect(scrollResult.availableArea));
+ mRenderer.renderView(view, viewCaptureArea);
+ onComplete.accept(new Rect(scrollResult.availableArea));
});
} else {
- long resultFrame = mRenderer.renderView(view, viewCaptureArea);
- session.notifyBufferSent(resultFrame, new Rect(scrollResult.availableArea));
+ mRenderer.renderView(view, viewCaptureArea);
+ onComplete.accept(new Rect(scrollResult.availableArea));
}
}
@@ -239,7 +257,7 @@
mCaptureRenderNode.endRecording();
}
- public long renderView(View view, Rect sourceRect) {
+ public void renderView(View view, Rect sourceRect) {
if (updateForView(view)) {
setupLighting(view);
}
@@ -258,7 +276,7 @@
switch (request.syncAndDraw()) {
case HardwareRenderer.SYNC_OK:
case HardwareRenderer.SYNC_REDRAW_REQUESTED:
- return frameNumber;
+ return;
case HardwareRenderer.SYNC_FRAME_DROPPED:
Log.e(TAG, "syncAndDraw(): SYNC_FRAME_DROPPED !");
@@ -270,7 +288,6 @@
Log.e(TAG, "syncAndDraw(): SYNC_CONTEXT_IS_STOPPED !");
break;
}
- return NO_FRAME_PRODUCED;
}
public void trimMemory() {
@@ -289,5 +306,17 @@
mTempMatrix.mapRect(mTempRectF);
mTempRectF.round(outRect);
}
+
+ public void setColorMode(@ColorMode int colorMode) {
+ mRenderer.setColorMode(colorMode);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ScrollCaptureViewSupport{"
+ + "view=" + mWeakView.get()
+ + ", helper=" + mViewHelper
+ + '}';
}
}
diff --git a/core/java/com/android/internal/widget/NotificationVanishingFrameLayout.java b/core/java/com/android/internal/widget/NotificationVanishingFrameLayout.java
new file mode 100644
index 0000000..742bdfd
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationVanishingFrameLayout.java
@@ -0,0 +1,70 @@
+/*
+ * 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.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+
+/**
+ * This view will measure itself as having 0 size if all of its children are {@link #GONE}.
+ * Otherwise it acts like a normal {@link FrameLayout}.
+ */
+@RemoteViews.RemoteView
+public class NotificationVanishingFrameLayout extends FrameLayout {
+ public NotificationVanishingFrameLayout(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public NotificationVanishingFrameLayout(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public NotificationVanishingFrameLayout(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public NotificationVanishingFrameLayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (allChildrenGone()) {
+ int zeroSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
+ super.onMeasure(zeroSpec, zeroSpec);
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ private boolean allChildrenGone() {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ if (child != null && child.getVisibility() != GONE) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 143017c..fd6038f 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -36,7 +36,6 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
-import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
@@ -60,9 +59,6 @@
*/
private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
- private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
- SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
-
public static class PointerState {
// Trace of previous points.
private float[] mTraceX = new float[32];
@@ -356,21 +352,6 @@
.toString(), 1 + itemW * 6, base, mTextPaint);
}
- int saveId = canvas.save();
- if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
- // Rotate negative (since we're rotating the drawing canvas vs the output).
- canvas.rotate(-90.0f * mContext.getDisplay().getRotation());
- switch (mContext.getDisplay().getRotation()) {
- case Surface.ROTATION_90:
- canvas.translate(-canvas.getHeight(), 0);
- break;
- case Surface.ROTATION_180:
- canvas.translate(-canvas.getWidth(), -canvas.getHeight());
- break;
- case Surface.ROTATION_270:
- canvas.translate(0, -canvas.getWidth());
- }
- }
// Pointer trace.
for (int p = 0; p < NP; p++) {
final PointerState ps = mPointers.get(p);
@@ -480,7 +461,6 @@
}
}
}
- canvas.restoreToCount(saveId);
}
private void logMotionEvent(String type, MotionEvent event) {
diff --git a/core/java/com/android/server/OWNERS b/core/java/com/android/server/OWNERS
new file mode 100644
index 0000000..12629254
--- /dev/null
+++ b/core/java/com/android/server/OWNERS
@@ -0,0 +1 @@
+per-file SystemConfig.java = toddke@google.com
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 671cb84..58df2be 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -24,6 +24,7 @@
import android.content.ComponentName;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
+import android.hardware.SensorPrivacyManager;
import android.os.Build;
import android.os.CarrierAssociatedAppEntry;
import android.os.Environment;
@@ -94,9 +95,6 @@
// property for runtime configuration differentiation in vendor
private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
- // property for background blur support in surface flinger
- private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur";
-
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
int[] mGlobalGids = EmptyArray.INT;
@@ -1248,8 +1246,12 @@
addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
}
- if (SystemProperties.get(BLUR_PROPERTY, "default").equals("1")) {
- addFeature(PackageManager.FEATURE_CROSS_LAYER_BLUR, 0);
+ if (SensorPrivacyManager.USE_MICROPHONE_TOGGLE) {
+ addFeature(PackageManager.FEATURE_MICROPHONE_TOGGLE, 0);
+ }
+
+ if (SensorPrivacyManager.USE_CAMERA_TOGGLE) {
+ addFeature(PackageManager.FEATURE_CAMERA_TOGGLE, 0);
}
for (String featureName : mUnavailableFeatures) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b485f0f..e6fb5ae 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -51,6 +51,7 @@
"android_util_XmlBlock.cpp",
"android_util_jar_StrictJarFile.cpp",
"com_android_internal_util_VirtualRefBasePtr.cpp",
+ ":deviceproductinfoconstants_aidl",
],
include_dirs: [
@@ -211,6 +212,7 @@
"com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp",
"com_android_internal_os_KernelSingleUidTimeReader.cpp",
"com_android_internal_os_Zygote.cpp",
+ "com_android_internal_os_ZygoteCommandBuffer.cpp",
"com_android_internal_os_ZygoteInit.cpp",
"hwbinder/EphemeralStorage.cpp",
"fd_utils.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index dc77bba..ddd8613 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -198,6 +198,7 @@
extern int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv* env);
extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
+extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
@@ -1531,6 +1532,7 @@
REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
REG_JNI(register_com_android_internal_os_Zygote),
+ REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
REG_JNI(register_android_hardware_Camera),
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 8d193bf..0e0f98e 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -861,6 +861,23 @@
return jStatus;
}
+static void android_media_AudioRecord_setLogSessionId(JNIEnv *env, jobject thiz,
+ jstring jlogSessionId) {
+ sp<AudioRecord> record = getAudioRecord(env, thiz);
+ if (record == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for setLogSessionId()");
+ }
+ if (jlogSessionId == nullptr) {
+ ALOGV("%s: logSessionId nullptr", __func__);
+ record->setLogSessionId(nullptr);
+ return;
+ }
+ ScopedUtfChars logSessionId(env, jlogSessionId);
+ ALOGV("%s: logSessionId '%s'", __func__, logSessionId.c_str());
+ record->setLogSessionId(logSessionId.c_str());
+}
+
// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_get_port_id(JNIEnv *env, jobject thiz) {
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -876,50 +893,48 @@
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
- // name, signature, funcPtr
- {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
- {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
- {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
- (void *)android_media_AudioRecord_setup},
- {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
- {"native_release", "()V", (void *)android_media_AudioRecord_release},
- {"native_read_in_byte_array",
- "([BIIZ)I",
- (void *)android_media_AudioRecord_readInArray<jbyteArray>},
- {"native_read_in_short_array",
- "([SIIZ)I",
- (void *)android_media_AudioRecord_readInArray<jshortArray>},
- {"native_read_in_float_array",
- "([FIIZ)I",
- (void *)android_media_AudioRecord_readInArray<jfloatArray>},
- {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
- (void *)android_media_AudioRecord_readInDirectBuffer},
- {"native_get_buffer_size_in_frames",
- "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
- {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos},
- {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos},
- {"native_set_pos_update_period",
- "(I)I", (void *)android_media_AudioRecord_set_pos_update_period},
- {"native_get_pos_update_period",
- "()I", (void *)android_media_AudioRecord_get_pos_update_period},
- {"native_get_min_buff_size",
- "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
- {"native_getMetrics", "()Landroid/os/PersistableBundle;",
- (void *)android_media_AudioRecord_native_getMetrics},
- {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
- {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
- {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
- {"native_disableDeviceCallback", "()V",
- (void *)android_media_AudioRecord_disableDeviceCallback},
- {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
- (void *)android_media_AudioRecord_get_timestamp},
- {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
- (void *)android_media_AudioRecord_get_active_microphones},
- {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
- {"native_set_preferred_microphone_direction", "(I)I",
- (void *)android_media_AudioRecord_set_preferred_microphone_direction},
- {"native_set_preferred_microphone_field_dimension", "(F)I",
- (void *)android_media_AudioRecord_set_preferred_microphone_field_dimension},
+ {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
+ {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
+ (void *)android_media_AudioRecord_setup},
+ {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
+ {"native_release", "()V", (void *)android_media_AudioRecord_release},
+ {"native_read_in_byte_array", "([BIIZ)I",
+ (void *)android_media_AudioRecord_readInArray<jbyteArray>},
+ {"native_read_in_short_array", "([SIIZ)I",
+ (void *)android_media_AudioRecord_readInArray<jshortArray>},
+ {"native_read_in_float_array", "([FIIZ)I",
+ (void *)android_media_AudioRecord_readInArray<jfloatArray>},
+ {"native_read_in_direct_buffer", "(Ljava/lang/Object;IZ)I",
+ (void *)android_media_AudioRecord_readInDirectBuffer},
+ {"native_get_buffer_size_in_frames", "()I",
+ (void *)android_media_AudioRecord_get_buffer_size_in_frames},
+ {"native_set_marker_pos", "(I)I", (void *)android_media_AudioRecord_set_marker_pos},
+ {"native_get_marker_pos", "()I", (void *)android_media_AudioRecord_get_marker_pos},
+ {"native_set_pos_update_period", "(I)I",
+ (void *)android_media_AudioRecord_set_pos_update_period},
+ {"native_get_pos_update_period", "()I",
+ (void *)android_media_AudioRecord_get_pos_update_period},
+ {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
+ {"native_getMetrics", "()Landroid/os/PersistableBundle;",
+ (void *)android_media_AudioRecord_native_getMetrics},
+ {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
+ {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
+ {"native_enableDeviceCallback", "()V",
+ (void *)android_media_AudioRecord_enableDeviceCallback},
+ {"native_disableDeviceCallback", "()V",
+ (void *)android_media_AudioRecord_disableDeviceCallback},
+ {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
+ (void *)android_media_AudioRecord_get_timestamp},
+ {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
+ (void *)android_media_AudioRecord_get_active_microphones},
+ {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
+ {"native_set_preferred_microphone_direction", "(I)I",
+ (void *)android_media_AudioRecord_set_preferred_microphone_direction},
+ {"native_set_preferred_microphone_field_dimension", "(F)I",
+ (void *)android_media_AudioRecord_set_preferred_microphone_field_dimension},
+ {"native_setLogSessionId", "(Ljava/lang/String;)V",
+ (void *)android_media_AudioRecord_setLogSessionId},
};
// field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index da60a75..cae6db5 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1426,8 +1426,13 @@
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setLogSessionId()");
}
+ if (jlogSessionId == nullptr) {
+ ALOGV("%s: logSessionId nullptr", __func__);
+ track->setLogSessionId(nullptr);
+ return;
+ }
ScopedUtfChars logSessionId(env, jlogSessionId);
- ALOGV("%s: logSessionId %s", __func__, logSessionId.c_str());
+ ALOGV("%s: logSessionId '%s'", __func__, logSessionId.c_str());
track->setLogSessionId(logSessionId.c_str());
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 451ea93..cbf4481 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -27,6 +27,7 @@
#include <android-base/chrono_utils.h>
#include <android/graphics/region.h>
#include <android/gui/BnScreenCaptureListener.h>
+#include <android/hardware/display/IDeviceProductInfoConstants.h>
#include <android/os/IInputConstants.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -1022,16 +1023,24 @@
} else {
LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
}
- auto relativeAddress = env->NewIntArray(info->relativeAddress.size());
- auto relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr);
- for (int i = 0; i < info->relativeAddress.size(); i++) {
- relativeAddressData[i] = info->relativeAddress[i];
+ jint connectionToSinkType;
+ // Relative address maps to HDMI physical address. All addresses are 4 digits long allowing
+ // for a 5–device-deep hierarchy. For more information, refer:
+ // Section 8.7 - Physical Address of HDMI Specification Version 1.3a
+ using android::hardware::display::IDeviceProductInfoConstants;
+ if (info->relativeAddress.size() != 4) {
+ connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
+ } else if (info->relativeAddress[0] == 0) {
+ connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN;
+ } else if (info->relativeAddress[1] == 0) {
+ connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_DIRECT;
+ } else {
+ connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_TRANSITIVE;
}
- env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0);
return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name,
manufacturerPnpId, productId, modelYear, manufactureDate,
- relativeAddress);
+ connectionToSinkType);
}
static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1970,7 +1979,7 @@
"Ljava/lang/String;"
"Ljava/lang/Integer;"
"Landroid/hardware/display/DeviceProductInfo$ManufactureDate;"
- "[I)V");
+ "I)V");
jclass deviceProductInfoManufactureDateClazz =
FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index e801725..c9062d8 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "Zygote"
#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include "com_android_internal_os_Zygote.h"
+
#include <async_safe/log.h>
// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
@@ -91,19 +93,6 @@
#include "nativebridge/native_bridge.h"
-/* Functions in the callchain during the fork shall not be protected with
- Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
-#ifdef __ARM_FEATURE_PAC_DEFAULT
-#ifdef __ARM_FEATURE_BTI_DEFAULT
-#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
-#else
-#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
-#endif /* __ARM_FEATURE_BTI_DEFAULT */
-#else /* !__ARM_FEATURE_PAC_DEFAULT */
-#define NO_PAC_FUNC
-#endif /* __ARM_FEATURE_PAC_DEFAULT */
-
-
namespace {
// TODO (chriswailes): Add a function to initialize native Zygote data.
@@ -118,8 +107,7 @@
using android::base::WriteStringToFile;
using android::base::GetBoolProperty;
-#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
- append(StringPrintf(__VA_ARGS__))
+using android::zygote::ZygoteFailure;
// This type is duplicated in fd_utils.h
typedef const std::function<void(std::string)>& fail_fn_t;
@@ -214,7 +202,7 @@
static constexpr EntryStorage INVALID_ENTRY_VALUE = {-1, -1};
std::atomic<EntryStorage> mStorage;
- static_assert(decltype(mStorage)::is_always_lock_free);
+ static_assert(decltype(mStorage)::is_always_lock_free); // Accessed from signal handler.
public:
constexpr UsapTableEntry() : mStorage(INVALID_ENTRY_VALUE) {}
@@ -917,36 +905,6 @@
}
/**
- * A failure function used to report fatal errors to the managed runtime. This
- * function is often curried with the process name information and then passed
- * to called functions.
- *
- * @param env Managed runtime environment
- * @param process_name A native representation of the process name
- * @param managed_process_name A managed representation of the process name
- * @param msg The error message to be reported
- */
-[[noreturn]]
-static void ZygoteFailure(JNIEnv* env,
- const char* process_name,
- jstring managed_process_name,
- const std::string& msg) {
- std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
- if (managed_process_name != nullptr) {
- scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name));
- if (scoped_managed_process_name_ptr->c_str() != nullptr) {
- process_name = scoped_managed_process_name_ptr->c_str();
- }
- }
-
- const std::string& error_msg =
- (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str());
-
- env->FatalError(error_msg.c_str());
- __builtin_unreachable();
-}
-
-/**
* A helper method for converting managed strings to native strings. A fatal
* error is generated if a problem is encountered in extracting a non-null
* string.
@@ -1073,86 +1031,6 @@
#endif
}
-// Utility routine to fork a process from the zygote.
-NO_PAC_FUNC
-static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
- const std::vector<int>& fds_to_close,
- const std::vector<int>& fds_to_ignore,
- bool is_priority_fork) {
- SetSignalHandlers();
-
- // Curry a failure function.
- auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
- nullptr, _1);
-
- // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
- // log, which would result in the logging FDs we close being reopened.
- // This would cause failures because the FDs are not allowlisted.
- //
- // Note that the zygote process is single threaded at this point.
- BlockSignal(SIGCHLD, fail_fn);
-
- // Close any logging related FDs before we start evaluating the list of
- // file descriptors.
- __android_log_close();
- AStatsSocket_close();
-
- // If this is the first fork for this zygote, create the open FD table. If
- // it isn't, we just need to check whether the list of open files has changed
- // (and it shouldn't in the normal case).
- if (gOpenFdTable == nullptr) {
- gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
- } else {
- gOpenFdTable->Restat(fds_to_ignore, fail_fn);
- }
-
- android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
-
- // Purge unused native memory in an attempt to reduce the amount of false
- // sharing with the child process. By reducing the size of the libc_malloc
- // region shared with the child process we reduce the number of pages that
- // transition to the private-dirty state when malloc adjusts the meta-data
- // on each of the pages it is managing after the fork.
- mallopt(M_PURGE, 0);
-
- pid_t pid = fork();
-
- if (pid == 0) {
- if (is_priority_fork) {
- setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
- } else {
- setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
- }
-
- // The child process.
- PAuthKeyChange(env);
- PreApplicationInit();
-
- // Clean up any descriptors which must be closed immediately
- DetachDescriptors(env, fds_to_close, fail_fn);
-
- // Invalidate the entries in the USAP table.
- ClearUsapTable();
-
- // Re-open all remaining open file descriptors so that they aren't shared
- // with the zygote across a fork.
- gOpenFdTable->ReopenOrDetach(fail_fn);
-
- // Turn fdsan back on.
- android_fdsan_set_error_level(fdsan_error_level);
-
- // Reset the fd to the unsolicited zygote socket
- gSystemServerSocketFd = -1;
- } else {
- ALOGD("Forked child process %d", pid);
- }
-
- // We blocked SIGCHLD prior to a fork, we unblock it here.
- UnblockSignal(SIGCHLD, fail_fn);
-
- return pid;
-}
-
// Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
// from the actual app data directory in data mirror.
static bool createAndMountAppData(std::string_view package_name,
@@ -1973,9 +1851,10 @@
static int sUsapTableInsertIndex = 0;
int search_index = sUsapTableInsertIndex;
-
do {
if (gUsapTable[search_index].SetIfInvalid(usap_pid, read_pipe_fd)) {
+ ++gUsapPoolCount;
+
// Start our next search right after where we finished this one.
sUsapTableInsertIndex = (search_index + 1) % gUsapTable.size();
@@ -1993,7 +1872,7 @@
/**
* Invalidates the entry in the USAPTable corresponding to the provided
* process ID if it is present. If an entry was removed the USAP pool
- * count is decremented.
+ * count is decremented. May be called from signal handler.
*
* @param usap_pid Process ID of the USAP entry to invalidate
* @return True if an entry was invalidated; false otherwise
@@ -2069,6 +1948,121 @@
namespace android {
+/**
+ * A failure function used to report fatal errors to the managed runtime. This
+ * function is often curried with the process name information and then passed
+ * to called functions.
+ *
+ * @param env Managed runtime environment
+ * @param process_name A native representation of the process name
+ * @param managed_process_name A managed representation of the process name
+ * @param msg The error message to be reported
+ */
+[[noreturn]]
+void zygote::ZygoteFailure(JNIEnv* env,
+ const char* process_name,
+ jstring managed_process_name,
+ const std::string& msg) {
+ std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
+ if (managed_process_name != nullptr) {
+ scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name));
+ if (scoped_managed_process_name_ptr->c_str() != nullptr) {
+ process_name = scoped_managed_process_name_ptr->c_str();
+ }
+ }
+
+ const std::string& error_msg =
+ (process_name == nullptr || process_name[0] == '\0') ?
+ msg : StringPrintf("(%s) %s", process_name, msg.c_str());
+
+ env->FatalError(error_msg.c_str());
+ __builtin_unreachable();
+}
+
+// Utility routine to fork a process from the zygote.
+NO_PAC_FUNC
+pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
+ const std::vector<int>& fds_to_close,
+ const std::vector<int>& fds_to_ignore,
+ bool is_priority_fork,
+ bool purge) {
+ SetSignalHandlers();
+
+ // Curry a failure function.
+ auto fail_fn = std::bind(zygote::ZygoteFailure, env,
+ is_system_server ? "system_server" : "zygote",
+ nullptr, _1);
+
+ // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
+ // log, which would result in the logging FDs we close being reopened.
+ // This would cause failures because the FDs are not allowlisted.
+ //
+ // Note that the zygote process is single threaded at this point.
+ BlockSignal(SIGCHLD, fail_fn);
+
+ // Close any logging related FDs before we start evaluating the list of
+ // file descriptors.
+ __android_log_close();
+ AStatsSocket_close();
+
+ // If this is the first fork for this zygote, create the open FD table. If
+ // it isn't, we just need to check whether the list of open files has changed
+ // (and it shouldn't in the normal case).
+ if (gOpenFdTable == nullptr) {
+ gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
+ } else {
+ gOpenFdTable->Restat(fds_to_ignore, fail_fn);
+ }
+
+ android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
+
+ if (purge) {
+ // Purge unused native memory in an attempt to reduce the amount of false
+ // sharing with the child process. By reducing the size of the libc_malloc
+ // region shared with the child process we reduce the number of pages that
+ // transition to the private-dirty state when malloc adjusts the meta-data
+ // on each of the pages it is managing after the fork.
+ mallopt(M_PURGE, 0);
+ }
+
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ if (is_priority_fork) {
+ setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
+ } else {
+ setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
+ }
+
+ // The child process.
+ PAuthKeyChange(env);
+ PreApplicationInit();
+
+ // Clean up any descriptors which must be closed immediately
+ DetachDescriptors(env, fds_to_close, fail_fn);
+
+ // Invalidate the entries in the USAP table.
+ ClearUsapTable();
+
+ // Re-open all remaining open file descriptors so that they aren't shared
+ // with the zygote across a fork.
+ gOpenFdTable->ReopenOrDetach(fail_fn);
+
+ // Turn fdsan back on.
+ android_fdsan_set_error_level(fdsan_error_level);
+
+ // Reset the fd to the unsolicited zygote socket
+ gSystemServerSocketFd = -1;
+ } else {
+ ALOGD("Forked child process %d", pid);
+ }
+
+ // We blocked SIGCHLD prior to a fork, we unblock it here.
+ UnblockSignal(SIGCHLD, fail_fn);
+
+ return pid;
+}
+
static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) {
PreApplicationInit();
}
@@ -2085,7 +2079,8 @@
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
if (UNLIKELY(managed_fds_to_close == nullptr)) {
- ZygoteFailure(env, "zygote", nice_name, "Zygote received a null fds_to_close vector.");
+ zygote::ZygoteFailure(env, "zygote", nice_name,
+ "Zygote received a null fds_to_close vector.");
}
std::vector<int> fds_to_close =
@@ -2111,7 +2106,7 @@
fds_to_ignore.push_back(gSystemServerSocketFd);
}
- pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
+ pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
@@ -2146,10 +2141,10 @@
fds_to_ignore.push_back(gSystemServerSocketFd);
}
- pid_t pid = ForkCommon(env, true,
- fds_to_close,
- fds_to_ignore,
- true);
+ pid_t pid = zygote::ForkCommon(env, true,
+ fds_to_close,
+ fds_to_ignore,
+ true);
if (pid == 0) {
// System server prcoess does not need data isolation so no need to
// know pkg_data_info_list.
@@ -2189,58 +2184,74 @@
* ensuring proper file descriptor hygiene.
*
* @param env Managed runtime environment
- * @param read_pipe_fd The read FD for the USAP reporting pipe. Manually closed by blastlas
- * in managed code.
+ * @param read_pipe_fd The read FD for the USAP reporting pipe. Manually closed by the child
+ * in managed code. -1 indicates none.
* @param write_pipe_fd The write FD for the USAP reporting pipe. Manually closed by the
- * zygote in managed code.
+ * zygote in managed code. -1 indicates none.
* @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by
* the FD hygiene code and automatically "closed" in the new USAP.
+ * @param args_known Arguments for specialization are available; no need to read from a socket
* @param is_priority_fork Controls the nice level assigned to the newly created process
- * @return
+ * @return child pid in the parent, 0 in the child
*/
NO_PAC_FUNC
-static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
- jclass,
- jint read_pipe_fd,
- jint write_pipe_fd,
- jintArray managed_session_socket_fds,
- jboolean is_priority_fork) {
- std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
- fds_to_ignore(fds_to_close);
-
+static jint com_android_internal_os_Zygote_nativeForkApp(JNIEnv* env,
+ jclass,
+ jint read_pipe_fd,
+ jint write_pipe_fd,
+ jintArray managed_session_socket_fds,
+ jboolean args_known,
+ jboolean is_priority_fork) {
std::vector<int> session_socket_fds =
ExtractJIntArray(env, "USAP", nullptr, managed_session_socket_fds)
.value_or(std::vector<int>());
+ return zygote::forkApp(env, read_pipe_fd, write_pipe_fd, session_socket_fds,
+ args_known == JNI_TRUE, is_priority_fork == JNI_TRUE, true);
+}
- // The USAP Pool Event FD is created during the initialization of the
- // USAP pool and should always be valid here.
+NO_PAC_FUNC
+int zygote::forkApp(JNIEnv* env,
+ int read_pipe_fd,
+ int write_pipe_fd,
+ const std::vector<int>& session_socket_fds,
+ bool args_known,
+ bool is_priority_fork,
+ bool purge) {
+
+ std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
+ fds_to_ignore(fds_to_close);
fds_to_close.push_back(gZygoteSocketFD);
- fds_to_close.push_back(gUsapPoolEventFD);
- fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end());
if (gSystemServerSocketFd != -1) {
fds_to_close.push_back(gSystemServerSocketFd);
}
+ if (args_known) {
+ fds_to_close.push_back(gUsapPoolSocketFD);
+ }
+ fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end());
- fds_to_ignore.push_back(gZygoteSocketFD);
fds_to_ignore.push_back(gUsapPoolSocketFD);
- fds_to_ignore.push_back(gUsapPoolEventFD);
- fds_to_ignore.push_back(read_pipe_fd);
- fds_to_ignore.push_back(write_pipe_fd);
+ fds_to_ignore.push_back(gZygoteSocketFD);
+ if (read_pipe_fd != -1) {
+ fds_to_ignore.push_back(read_pipe_fd);
+ }
+ if (write_pipe_fd != -1) {
+ fds_to_ignore.push_back(write_pipe_fd);
+ }
fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end());
+
+ if (gUsapPoolEventFD != -1) {
+ fds_to_close.push_back(gUsapPoolEventFD);
+ fds_to_ignore.push_back(gUsapPoolEventFD);
+ }
if (gSystemServerSocketFd != -1) {
+ if (args_known) {
+ fds_to_close.push_back(gSystemServerSocketFd);
+ }
fds_to_ignore.push_back(gSystemServerSocketFd);
}
-
- pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore,
- is_priority_fork == JNI_TRUE);
-
- if (usap_pid != 0) {
- ++gUsapPoolCount;
- AddUsapTableEntry(usap_pid, read_pipe_fd);
- }
-
- return usap_pid;
+ return zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close,
+ fds_to_ignore, is_priority_fork == JNI_TRUE, purge);
}
static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
@@ -2354,7 +2365,7 @@
*/
if (!SetTaskProfiles(0, {})) {
- ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
+ zygote::ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
}
}
@@ -2372,15 +2383,21 @@
return managed_usap_fds;
}
+/*
+ * Add the given pid and file descriptor to the Usap table. CriticalNative method.
+ */
+static void com_android_internal_os_Zygote_nativeAddUsapTableEntry(jint pid, jint read_pipe_fd) {
+ AddUsapTableEntry(pid, read_pipe_fd);
+}
+
/**
- * A JNI wrapper around RemoveUsapTableEntry.
+ * A JNI wrapper around RemoveUsapTableEntry. CriticalNative method.
*
* @param env Managed runtime environment
* @param usap_pid Process ID of the USAP entry to invalidate
* @return True if an entry was invalidated; false otherwise.
*/
-static jboolean com_android_internal_os_Zygote_nativeRemoveUsapTableEntry(JNIEnv* env, jclass,
- jint usap_pid) {
+static jboolean com_android_internal_os_Zygote_nativeRemoveUsapTableEntry(jint usap_pid) {
return RemoveUsapTableEntry(usap_pid);
}
@@ -2395,7 +2412,8 @@
static jint com_android_internal_os_Zygote_nativeGetUsapPoolEventFD(JNIEnv* env, jclass) {
if (gUsapPoolEventFD == -1) {
if ((gUsapPoolEventFD = eventfd(0, 0)) == -1) {
- ZygoteFailure(env, "zygote", nullptr, StringPrintf("Unable to create eventfd: %s", strerror(errno)));
+ zygote::ZygoteFailure(env, "zygote", nullptr,
+ StringPrintf("Unable to create eventfd: %s", strerror(errno)));
}
}
@@ -2438,12 +2456,12 @@
}
static void com_android_internal_os_Zygote_nativeBlockSigTerm(JNIEnv* env, jclass) {
- auto fail_fn = std::bind(ZygoteFailure, env, "usap", nullptr, _1);
+ auto fail_fn = std::bind(zygote::ZygoteFailure, env, "usap", nullptr, _1);
BlockSignal(SIGTERM, fail_fn);
}
static void com_android_internal_os_Zygote_nativeUnblockSigTerm(JNIEnv* env, jclass) {
- auto fail_fn = std::bind(ZygoteFailure, env, "usap", nullptr, _1);
+ auto fail_fn = std::bind(zygote::ZygoteFailure, env, "usap", nullptr, _1);
UnblockSignal(SIGTERM, fail_fn);
}
@@ -2549,7 +2567,10 @@
(void*)com_android_internal_os_Zygote_nativePreApplicationInit},
{"nativeInstallSeccompUidGidFilter", "(II)V",
(void*)com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter},
- {"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap},
+ {"nativeForkApp", "(II[IZZ)I", (void*)com_android_internal_os_Zygote_nativeForkApp},
+ // @CriticalNative
+ {"nativeAddUsapTableEntry", "(II)V",
+ (void*)com_android_internal_os_Zygote_nativeAddUsapTableEntry},
{"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/"
"String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
@@ -2558,6 +2579,10 @@
(void*)com_android_internal_os_Zygote_nativeInitNativeState},
{"nativeGetUsapPipeFDs", "()[I",
(void*)com_android_internal_os_Zygote_nativeGetUsapPipeFDs},
+ // @CriticalNative
+ {"nativeAddUsapTableEntry", "(II)V",
+ (void*)com_android_internal_os_Zygote_nativeAddUsapTableEntry},
+ // @CriticalNative
{"nativeRemoveUsapTableEntry", "(I)Z",
(void*)com_android_internal_os_Zygote_nativeRemoveUsapTableEntry},
{"nativeGetUsapPoolEventFD", "()I",
diff --git a/core/jni/com_android_internal_os_Zygote.h b/core/jni/com_android_internal_os_Zygote.h
new file mode 100644
index 0000000..d2da914
--- /dev/null
+++ b/core/jni/com_android_internal_os_Zygote.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef _COM_ANDROID_INTERNAL_OS_ZYGOTE_H
+#define _COM_ANDROID_INTERNAL_OS_ZYGOTE_H
+
+#define LOG_TAG "Zygote"
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
+/* Functions in the callchain during the fork shall not be protected with
+ Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
+#else
+#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
+#endif /* __ARM_FEATURE_BTI_DEFAULT */
+#else /* !__ARM_FEATURE_PAC_DEFAULT */
+#define NO_PAC_FUNC
+#endif /* __ARM_FEATURE_PAC_DEFAULT */
+
+#include <jni.h>
+#include <vector>
+#include <android-base/stringprintf.h>
+
+#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
+ append(StringPrintf(__VA_ARGS__))
+
+namespace android {
+namespace zygote {
+
+NO_PAC_FUNC
+pid_t ForkCommon(JNIEnv* env,bool is_system_server,
+ const std::vector<int>& fds_to_close,
+ const std::vector<int>& fds_to_ignore,
+ bool is_priority_fork,
+ bool purge = true);
+
+/**
+ * Fork a process. The pipe fds are used for usap communication, or -1 in
+ * other cases. Session_socket_fds are FDs used for zygote communication that must be dealt
+ * with hygienically, but are not otherwise used here. Args_known indicates that the process
+ * will be immediately specialized with arguments that are already known, so no usap
+ * communication is required. Is_priority_fork should be true if this is on the app startup
+ * critical path. Purge specifies that unused pages should be purged before the fork.
+ */
+NO_PAC_FUNC
+int forkApp(JNIEnv* env,
+ int read_pipe_fd,
+ int write_pipe_fd,
+ const std::vector<int>& session_socket_fds,
+ bool args_known,
+ bool is_priority_fork,
+ bool purge);
+
+[[noreturn]]
+void ZygoteFailure(JNIEnv* env,
+ const char* process_name,
+ jstring managed_process_name,
+ const std::string& msg);
+
+} // namespace zygote
+} // namespace android
+
+#endif // _COM_ANDROID_INTERNAL_OS_ZYGOTE_
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
new file mode 100644
index 0000000..011e8f8
--- /dev/null
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -0,0 +1,512 @@
+/*
+ * 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.
+ */
+
+#include "com_android_internal_os_Zygote.h"
+
+#include <algorithm>
+#include <android-base/logging.h>
+#include <async_safe/log.h>
+#include <cctype>
+#include <chrono>
+#include <core_jni_helpers.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <optional>
+#include <poll.h>
+#include <unistd.h>
+#include <utility>
+#include <utils/misc.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <vector>
+
+namespace android {
+
+using namespace std::placeholders;
+using android::base::StringPrintf;
+using android::zygote::ZygoteFailure;
+
+// WARNING: Knows a little about the wire protocol used to communicate with Zygote.
+// TODO: Fix error handling.
+
+constexpr size_t MAX_COMMAND_BYTES = 12200;
+constexpr size_t NICE_NAME_BYTES = 50;
+
+// A buffer optionally bundled with a file descriptor from which we can fill it.
+// Does not own the file descriptor; destroying a NativeCommandBuffer does not
+// close the descriptor.
+class NativeCommandBuffer {
+ public:
+ NativeCommandBuffer(int sourceFd): mEnd(0), mNext(0), mLinesLeft(0), mFd(sourceFd) {}
+
+ // Read mNext line from mFd, filling mBuffer from file descriptor, as needed.
+ // Return a pair of pointers pointing to the first character, and one past the
+ // mEnd of the line, i.e. at the newline. Returns nothing on failure.
+ template<class FailFn>
+ std::optional<std::pair<char*, char*>> readLine(FailFn fail_fn) {
+ char* result = mBuffer + mNext;
+ while (true) {
+ if (mNext == mEnd) {
+ if (mEnd == MAX_COMMAND_BYTES) {
+ return {};
+ }
+ if (mFd == -1) {
+ fail_fn("ZygoteCommandBuffer.readLine attempted to read from mFd -1");
+ }
+ ssize_t nread = TEMP_FAILURE_RETRY(read(mFd, mBuffer + mEnd, MAX_COMMAND_BYTES - mEnd));
+ if (nread <= 0) {
+ if (nread == 0) {
+ return {};
+ }
+ fail_fn(CREATE_ERROR("session socket read failed: %s", strerror(errno)));
+ } else if (nread == MAX_COMMAND_BYTES - mEnd) {
+ // This is pessimistic by one character, but close enough.
+ fail_fn("ZygoteCommandBuffer overflowed: command too long");
+ }
+ mEnd += nread;
+ }
+ // UTF-8 does not allow newline to occur as part of a multibyte character.
+ char* nl = static_cast<char *>(memchr(mBuffer + mNext, '\n', mEnd - mNext));
+ if (nl == nullptr) {
+ mNext = mEnd;
+ } else {
+ mNext = nl - mBuffer + 1;
+ if (--mLinesLeft < 0) {
+ fail_fn("ZygoteCommandBuffer.readLine attempted to read past mEnd of command");
+ }
+ return std::make_pair(result, nl);
+ }
+ }
+ }
+
+ void reset() {
+ mNext = 0;
+ }
+
+ // Make sure the current command is fully buffered, without reading past the current command.
+ template<class FailFn>
+ void readAllLines(FailFn fail_fn) {
+ while (mLinesLeft > 0) {
+ readLine(fail_fn);
+ }
+ }
+
+ void clear() {
+ // Don't bother to actually clear the buffer; it'll be unmapped in the child anyway.
+ reset();
+ mNiceName[0] = '\0';
+ mEnd = 0;
+ }
+
+ // Insert line into the mBuffer. Checks that the mBuffer is not associated with an mFd.
+ // Implicitly adds newline separators. Allows mBuffer contents to be explicitly set.
+ void insert(const char* line, size_t lineLen) {
+ DCHECK(mFd == -1);
+ CHECK(mEnd + lineLen < MAX_COMMAND_BYTES);
+ strncpy(mBuffer + mEnd, line, lineLen);
+ mBuffer[mEnd + lineLen] = '\n';
+ mEnd += lineLen + 1;
+ }
+
+ // Clear mBuffer, start reading new command, return the number of arguments, leaving mBuffer
+ // positioned at the beginning of first argument. Return 0 on EOF.
+ template<class FailFn>
+ int getCount(FailFn fail_fn) {
+ mLinesLeft = 1;
+ auto line = readLine(fail_fn);
+ if (!line.has_value()) {
+ return 0;
+ }
+ char* countString = line.value().first; // Newline terminated.
+ long nArgs = atol(countString);
+ if (nArgs <= 0 || nArgs >= MAX_COMMAND_BYTES / 2) {
+ fail_fn(CREATE_ERROR("Unreasonable argument count %ld", nArgs));
+ }
+ mLinesLeft = nArgs;
+ return static_cast<int>(nArgs);
+ }
+
+ // Is the mBuffer a simple fork command?
+ // We disallow request to wrap the child process, child zygotes, anything that
+ // mentions capabilities or requests uid < minUid.
+ // We insist that --setuid and --setgid arguments are explicitly included and that the
+ // command starts with --runtime-args.
+ // Assumes we are positioned at the beginning of the command after the argument count,
+ // and leaves the position at some indeterminate position in the buffer.
+ // As a side effect, this sets mNiceName to a non-empty string, if possible.
+ template<class FailFn>
+ bool isSimpleForkCommand(int minUid, FailFn fail_fn) {
+ if (mLinesLeft <= 0 || mLinesLeft >= MAX_COMMAND_BYTES / 2) {
+ return false;
+ }
+ static const char* RUNTIME_ARGS = "--runtime-args";
+ static const char* INVOKE_WITH = "--invoke-with";
+ static const char* CHILD_ZYGOTE = "--start-child-zygote";
+ static const char* SETUID = "--setuid=";
+ static const char* SETGID = "--setgid=";
+ static const char* CAPABILITIES = "--capabilities";
+ static const char* NICE_NAME = "--nice-name=";
+ static const size_t RA_LENGTH = strlen(RUNTIME_ARGS);
+ static const size_t IW_LENGTH = strlen(INVOKE_WITH);
+ static const size_t CZ_LENGTH = strlen(CHILD_ZYGOTE);
+ static const size_t SU_LENGTH = strlen(SETUID);
+ static const size_t SG_LENGTH = strlen(SETGID);
+ static const size_t CA_LENGTH = strlen(CAPABILITIES);
+ static const size_t NN_LENGTH = strlen(NICE_NAME);
+
+ bool saw_setuid = false, saw_setgid = false;
+ bool saw_runtime_args = false;
+
+ while (mLinesLeft > 0) {
+ auto read_result = readLine(fail_fn);
+ if (!read_result.has_value()) {
+ return false;
+ }
+ auto [arg_start, arg_end] = read_result.value();
+ if (arg_end - arg_start == RA_LENGTH
+ && strncmp(arg_start, RUNTIME_ARGS, RA_LENGTH) == 0) {
+ saw_runtime_args = true;
+ continue;
+ }
+ if (arg_end - arg_start >= NN_LENGTH
+ && strncmp(arg_start, NICE_NAME, NN_LENGTH) == 0) {
+ size_t name_len = arg_end - (arg_start + NN_LENGTH);
+ size_t copy_len = std::min(name_len, NICE_NAME_BYTES - 1);
+ memcpy(mNiceName, arg_start + NN_LENGTH, copy_len);
+ mNiceName[copy_len] = '\0';
+ continue;
+ }
+ if (arg_end - arg_start == IW_LENGTH
+ && strncmp(arg_start, INVOKE_WITH, IW_LENGTH) == 0) {
+ // This also removes the need for invoke-with security checks here.
+ return false;
+ }
+ if (arg_end - arg_start == CZ_LENGTH
+ && strncmp(arg_start, CHILD_ZYGOTE, CZ_LENGTH) == 0) {
+ return false;
+ }
+ if (arg_end - arg_start >= CA_LENGTH
+ && strncmp(arg_start, CAPABILITIES, CA_LENGTH) == 0) {
+ return false;
+ }
+ if (arg_end - arg_start >= SU_LENGTH
+ && strncmp(arg_start, SETUID, SU_LENGTH) == 0) {
+ int uid = digitsVal(arg_start + SU_LENGTH, arg_end);
+ if (uid < minUid) {
+ return false;
+ }
+ saw_setuid = true;
+ continue;
+ }
+ if (arg_end - arg_start >= SG_LENGTH
+ && strncmp(arg_start, SETGID, SG_LENGTH) == 0) {
+ int gid = digitsVal(arg_start + SG_LENGTH, arg_end);
+ if (gid == -1) {
+ return false;
+ }
+ saw_setgid = true;
+ }
+ }
+ return saw_runtime_args && saw_setuid && saw_setgid;
+ }
+
+ void setFd(int new_fd) {
+ mFd = new_fd;
+ }
+
+ int getFd() const {
+ return mFd;
+ }
+
+ const char* niceNameAddr() const {
+ return mNiceName;
+ }
+
+ // Debug only:
+ void logState() const {
+ ALOGD("mbuffer starts with %c%c, nice name is %s, "
+ "mEnd = %u, mNext = %u, mLinesLeft = %d, mFd = %d",
+ mBuffer[0], (mBuffer[1] == '\n' ? ' ' : mBuffer[1]),
+ niceNameAddr(),
+ static_cast<unsigned>(mEnd), static_cast<unsigned>(mNext),
+ static_cast<int>(mLinesLeft), mFd);
+ }
+
+ private:
+ // Picky version of atoi(). No sign or unexpected characters allowed. Return -1 on failure.
+ static int digitsVal(char* start, char* end) {
+ int result = 0;
+ if (end - start > 6) {
+ return -1;
+ }
+ for (char* dp = start; dp < end; ++dp) {
+ if (*dp < '0' || *dp > '9') {
+ ALOGW("Argument failed integer format check");
+ return -1;
+ }
+ result = 10 * result + (*dp - '0');
+ }
+ return result;
+ }
+
+ uint32_t mEnd; // Index of first empty byte in the mBuffer.
+ uint32_t mNext; // Index of first character past last line returned by readLine.
+ int32_t mLinesLeft; // Lines in current command that haven't yet been read.
+ int mFd; // Open file descriptor from which we can read more. -1 if none.
+ char mNiceName[NICE_NAME_BYTES];
+ char mBuffer[MAX_COMMAND_BYTES];
+};
+
+static_assert(sizeof(NativeCommandBuffer) < 3 * 4096);
+
+static int buffersAllocd(0);
+
+// Get a new NativeCommandBuffer. Can only be called once between freeNativeBuffer calls,
+// so that only one buffer exists at a time.
+jlong com_android_internal_os_ZygoteCommandBuffer_getNativeBuffer(JNIEnv* env, jclass, jint fd) {
+ CHECK(buffersAllocd == 0);
+ ++buffersAllocd;
+ // MMap explicitly to get it page aligned.
+ void *bufferMem = mmap(NULL, sizeof(NativeCommandBuffer), PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, -1, 0);
+ // Currently we mmap and unmap one for every request handled by the Java code.
+ // That could be improved, but unclear it matters.
+ if (bufferMem == MAP_FAILED) {
+ ZygoteFailure(env, nullptr, nullptr, "Failed to map argument buffer");
+ }
+ return (jlong) new(bufferMem) NativeCommandBuffer(fd);
+}
+
+// Delete native command buffer.
+void com_android_internal_os_ZygoteCommandBuffer_freeNativeBuffer(JNIEnv* env, jclass,
+ jlong j_buffer) {
+ CHECK(buffersAllocd == 1);
+ NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+ n_buffer->~NativeCommandBuffer();
+ if (munmap(n_buffer, sizeof(NativeCommandBuffer)) != 0) {
+ ZygoteFailure(env, nullptr, nullptr, "Failed to unmap argument buffer");
+ }
+ --buffersAllocd;
+}
+
+// Clear the buffer, read the line containing the count, and return the count.
+jint com_android_internal_os_ZygoteCommandBuffer_nativeGetCount(JNIEnv* env, jclass,
+ jlong j_buffer) {
+ NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+ auto fail_fn = std::bind(ZygoteFailure, env, nullptr, nullptr, _1);
+ return n_buffer->getCount(fail_fn);
+}
+
+// Explicitly insert a string as the last line (argument) of the buffer.
+void com_android_internal_os_ZygoteCommandBuffer_insert(JNIEnv* env, jclass, jlong j_buffer,
+ jstring line) {
+ NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+ size_t lineLen = static_cast<size_t>(env->GetStringUTFLength(line));
+ const char* cstring = env->GetStringUTFChars(line, NULL);
+ n_buffer->insert(cstring, lineLen);
+ env->ReleaseStringUTFChars(line, cstring);
+}
+
+// Read a line from the buffer, refilling as necessary.
+jstring com_android_internal_os_ZygoteCommandBuffer_nativeNextArg(JNIEnv* env, jclass,
+ jlong j_buffer) {
+ NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+ auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1);
+ auto line = n_buffer->readLine(fail_fn);
+ if (!line.has_value()) {
+ fail_fn("Incomplete zygote command");
+ }
+ auto [cresult, endp] = line.value();
+ // OK to temporarily clobber the buffer, since this is not thread safe, and we're modifying
+ // the buffer anyway.
+ *endp = '\0';
+ jstring result = env->NewStringUTF(cresult);
+ *endp = '\n';
+ return result;
+}
+
+// Read all lines from the current command into the buffer, and then reset the buffer, so
+// we will start reading again at the beginning of the command, starting with the argument
+// count. And we don't need access to the fd to do so.
+void com_android_internal_os_ZygoteCommandBuffer_nativeReadFullyAndReset(JNIEnv* env, jclass,
+ jlong j_buffer) {
+ NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+ auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1);
+ n_buffer->readAllLines(fail_fn);
+ n_buffer->reset();
+}
+
+// Fork a child as specified by the current command buffer, and refill the command
+// buffer from the given socket. So long as the result is another simple fork command,
+// repeat this process.
+// It must contain a fork command, which is currently restricted not to fork another
+// zygote or involve a wrapper process.
+// The initial buffer should be partially or entirely read; we read it fully and reset it.
+// When we return, the buffer contains the command we couldn't handle, and has been reset().
+// We return false in the parent when we see a command we didn't understand, and thus the
+// command in the buffer still needs to be executed.
+// We return true in each child.
+// We only process fork commands if the peer uid matches expected_uid.
+// For every fork command after the first, we check that the requested uid is at
+// least minUid.
+NO_PAC_FUNC
+jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
+ JNIEnv* env,
+ jclass,
+ jlong j_buffer,
+ jint zygote_socket_fd,
+ jint expected_uid,
+ jint minUid,
+ jstring managed_nice_name) {
+
+ NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+ int session_socket = n_buffer->getFd();
+ std::vector<int> session_socket_fds {session_socket};
+ auto fail_fn_1 = std::bind(ZygoteFailure, env, static_cast<const char*>(nullptr),
+ static_cast<jstring>(managed_nice_name), _1);
+ // This binds to the nice name address; the actual names are updated by isSimpleForkCommand:
+ auto fail_fn_n = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(),
+ static_cast<jstring>(nullptr), _1);
+ auto fail_fn_z = std::bind(ZygoteFailure, env, "zygote", nullptr, _1);
+
+ struct pollfd fd_structs[2];
+ static const int ZYGOTE_IDX = 0;
+ static const int SESSION_IDX = 1;
+ fd_structs[ZYGOTE_IDX].fd = zygote_socket_fd;
+ fd_structs[ZYGOTE_IDX].events = POLLIN;
+ fd_structs[SESSION_IDX].fd = session_socket;
+ fd_structs[SESSION_IDX].events = POLLIN;
+
+ struct timeval timeout;
+ socklen_t timeout_size = sizeof timeout;
+ if (getsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, &timeout_size) != 0) {
+ fail_fn_z("Failed to retrieve session socket timeout");
+ }
+
+ struct ucred credentials;
+ socklen_t cred_size = sizeof credentials;
+ if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1
+ || cred_size != sizeof credentials) {
+ fail_fn_1("ForkMany failed to get initial credentials, %s", strerror(errno));
+ }
+
+ bool first_time = true;
+ do {
+ if (credentials.uid != expected_uid) {
+ return JNI_FALSE;
+ }
+ n_buffer->readAllLines(first_time ? fail_fn_1 : fail_fn_n);
+ n_buffer->reset();
+ int pid = zygote::forkApp(env, /* no pipe FDs */ -1, -1, session_socket_fds,
+ /*args_known=*/ true, /*is_priority_fork=*/ true,
+ /*purge=*/ first_time);
+ if (pid == 0) {
+ return JNI_TRUE;
+ }
+ // We're in the parent. Write big-endian pid, followed by a boolean.
+ char pid_buf[5];
+ int tmp_pid = pid;
+ for (int i = 3; i >= 0; --i) {
+ pid_buf[i] = tmp_pid & 0xff;
+ tmp_pid >>= 8;
+ }
+ pid_buf[4] = 0; // Process is not wrapped.
+ int res = write(session_socket, pid_buf, 5);
+ if (res != 5) {
+ if (res == -1) {
+ (first_time ? fail_fn_1 : fail_fn_n)
+ (CREATE_ERROR("Pid write error %d: %s", errno, strerror(errno)));
+ } else {
+ (first_time ? fail_fn_1 : fail_fn_n)
+ (CREATE_ERROR("Write unexpectedly returned short: %d < 5", res));
+ }
+ }
+ // Clear buffer and get count from next command.
+ n_buffer->clear();
+ for (;;) {
+ // Poll isn't strictly necessary for now. But without it, disconnect is hard to detect.
+ int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */));
+ if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) {
+ if (n_buffer->getCount(fail_fn_z) != 0) {
+ break;
+ } // else disconnected;
+ } else if (poll_res == 0 || (fd_structs[ZYGOTE_IDX].revents & POLLIN) == 0) {
+ fail_fn_z(
+ CREATE_ERROR("Poll returned with no descriptors ready! Poll returned %d", poll_res));
+ }
+ // We've now seen either a disconnect or connect request.
+ close(session_socket);
+ int new_fd = accept(zygote_socket_fd, nullptr, nullptr);
+ if (new_fd == -1) {
+ fail_fn_z("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno));
+ }
+ if (new_fd != session_socket) {
+ // Move new_fd back to the old value, so that we don't have to change Java-level data
+ // structures to reflect a change. This implicitly closes the old one.
+ if (dup2(new_fd, session_socket) != session_socket) {
+ fail_fn_z(CREATE_ERROR("Failed to move fd %d to %d: %s",
+ new_fd, session_socket, strerror(errno)));
+ }
+ close(new_fd);
+ }
+ // If we ever return, we effectively reuse the old Java ZygoteConnection.
+ // None of its state needs to change.
+ if (setsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, timeout_size) != 0) {
+ fail_fn_z(CREATE_ERROR("Failed to set receive timeout for socket %d: %s",
+ session_socket, strerror(errno)));
+ }
+ if (setsockopt(session_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, timeout_size) != 0) {
+ fail_fn_z(CREATE_ERROR("Failed to set send timeout for socket %d: %s",
+ session_socket, strerror(errno)));
+ }
+ if (getsockopt(session_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1) {
+ fail_fn_z(CREATE_ERROR("ForkMany failed to get credentials: %s", strerror(errno)));
+ }
+ if (cred_size != sizeof credentials) {
+ fail_fn_z(CREATE_ERROR("ForkMany credential size = %d, should be %d",
+ cred_size, static_cast<int>(sizeof credentials)));
+ }
+ }
+ first_time = false;
+ } while (n_buffer->isSimpleForkCommand(minUid, fail_fn_n));
+ ALOGW("forkRepeatedly terminated due to non-simple command");
+ n_buffer->logState();
+ n_buffer->reset();
+ return JNI_FALSE;
+}
+
+#define METHOD_NAME(m) com_android_internal_os_ZygoteCommandBuffer_ ## m
+
+static const JNINativeMethod gMethods[] = {
+ {"getNativeBuffer", "(I)J", (void *) METHOD_NAME(getNativeBuffer)},
+ {"freeNativeBuffer", "(J)V", (void *) METHOD_NAME(freeNativeBuffer)},
+ {"insert", "(JLjava/lang/String;)V", (void *) METHOD_NAME(insert)},
+ {"nativeNextArg", "(J)Ljava/lang/String;", (void *) METHOD_NAME(nativeNextArg)},
+ {"nativeReadFullyAndReset", "(J)V", (void *) METHOD_NAME(nativeReadFullyAndReset)},
+ {"nativeGetCount", "(J)I", (void *) METHOD_NAME(nativeGetCount)},
+ {"nativeForkRepeatedly", "(JIIILjava/lang/String;)Z",
+ (void *) METHOD_NAME(nativeForkRepeatedly)},
+};
+
+int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "com/android/internal/os/ZygoteCommandBuffer", gMethods,
+ NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c580b34..ad1d252 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -282,7 +282,8 @@
optional SettingProto force_rtl = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto emulate_display_cutout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto force_desktop_mode_on_external_displays = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Deprecated, use enable_non_resizable_multi_window
+ optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC, deprecated = true ];
optional SettingProto enable_non_resizable_multi_window = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Development development = 39;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index d3c2d31..ec41a47 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -627,6 +627,7 @@
optional int64 duration_ms = 2;
optional string tag = 3;
optional int32 type = 4;
+ optional int32 reason_code = 5;
}
repeated PendingTempWhitelist pending_temp_whitelist = 26;
diff --git a/core/proto/android/server/powerstatsservice.proto b/core/proto/android/server/powerstatsservice.proto
index 4b1ee02..f64e146 100644
--- a/core/proto/android/server/powerstatsservice.proto
+++ b/core/proto/android/server/powerstatsservice.proto
@@ -144,7 +144,7 @@
*/
optional int64 total_state_entry_count = 3;
/**
- * Last time this state was entered. Time in milliseconds since boot
+ * Last time this state was entered. Walltime in milliseconds since Unix epoch.
*/
optional int64 last_entry_timestamp_ms = 4;
}
@@ -208,7 +208,7 @@
/** Unique index identifying the energy consumer. */
optional int32 id = 1;
- /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */
+ /** Walltime in milliseconds since Unix epoch */
optional int64 timestamp_ms = 2;
/** Accumulated energy since device boot in microwatt-seconds (uWs) */
@@ -247,7 +247,7 @@
*/
optional int32 id = 1;
- /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */
+ /** Walltime in milliseconds since Unix epoch */
optional int64 timestamp_ms = 2;
/** Accumulated energy since device boot in microwatt-seconds (uWs) */
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
index 8ebb4a9..c8cdfdd 100644
--- a/core/proto/android/service/netstats.proto
+++ b/core/proto/android/service/netstats.proto
@@ -80,6 +80,8 @@
optional bool metered = 5;
optional bool default_network = 6;
+
+ optional int32 oem_managed_network = 7;
}
// Corresponds to NetworkStatsRecorder.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7ad016c..d5f5d28 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1284,15 +1284,15 @@
android:backgroundPermission="android.permission.RECORD_BACKGROUND_AUDIO"
android:protectionLevel="dangerous|instant" />
- <!-- Allows an application to record audio while in the background.
- <p>Protection level: dangerous
- -->
+ <!-- @SystemApi @TestApi Allows an application to record audio while in the background.
+ This permission is not intended to be held by apps.
+ <p>Protection level: internal
+ @hide -->
<permission android:name="android.permission.RECORD_BACKGROUND_AUDIO"
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_recordBackgroundAudio"
android:description="@string/permdesc_recordBackgroundAudio"
- android:permissionFlags="hardRestricted|installerExemptIgnored"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="internal" />
<!-- ====================================================================== -->
<!-- Permissions for activity recognition -->
@@ -1368,15 +1368,15 @@
android:backgroundPermission="android.permission.BACKGROUND_CAMERA"
android:protectionLevel="dangerous|instant" />
- <!-- Required to be able to access the camera device in the background.
- <p>Protection level: dangerous
- -->
+ <!-- @SystemApi @TestApi Required to be able to access the camera device in the background.
+ This permission is not intended to be held by apps.
+ <p>Protection level: internal
+ @hide -->
<permission android:name="android.permission.BACKGROUND_CAMERA"
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_backgroundCamera"
android:description="@string/permdesc_backgroundCamera"
- android:permissionFlags="hardRestricted|installerExemptIgnored"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="internal" />
<!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
system only camera devices.
@@ -3982,17 +3982,6 @@
<permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
android:protectionLevel="signature|privileged" />
- <!-- Allows an application to use the package installer v2 APIs.
- <p>The package installer v2 APIs are still a work in progress and we're
- currently validating they work in all scenarios.
- <p>Not for use by third-party applications.
- TODO(b/152310230): use this permission to protect only Incremental installations
- once the APIs are confirmed to be sufficient.
- @hide
- -->
- <permission android:name="com.android.permission.USE_INSTALLER_V2"
- android:protectionLevel="signature|verifier" />
-
<!-- Allows an application to use System Data Loaders.
<p>Not for use by third-party applications.
@hide
@@ -5431,6 +5420,12 @@
@hide -->
<permission android:name="android.permission.MANAGE_SENSOR_PRIVACY"
android:protectionLevel="signature" />
+
+ <!-- @SystemApi Allows sensor privacy changes to be observed.
+ @hide -->
+ <permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY"
+ android:protectionLevel="signature|installer" />
+
<!-- @SystemApi Permission that protects the {@link Intent#ACTION_REVIEW_ACCESSIBILITY_SERVICES}
intent.
@hide -->
diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml
index 302a388..e01d803 100644
--- a/core/res/res/layout/notification_template_conversation_header.xml
+++ b/core/res/res/layout/notification_template_conversation_header.xml
@@ -99,13 +99,26 @@
android:visibility="gone"
/>
+ <TextView
+ android:id="@+id/verification_divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
+ 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"
+ />
+
<ImageView
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:contentDescription="@string/notification_alerted_content_description"
android:paddingTop="2dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_notifications_alerted"
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index d79cb74..b83611bc 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -91,26 +91,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginBottom="@dimen/notification_headerless_margin_minimum"
- android:layout_marginTop="@dimen/notification_headerless_margin_minimum"
+ android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+ android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
android:orientation="vertical"
>
- <!--
- This invisible FrameLayout is here as a collapsible padding. Having a layout_weight=1 is
- what causes this view (and it's counterpart at the opposite end) to collapse before the
- actual content views do.
- This pair of 10dp collapsible paddings (plus the 16dp fixed margins) allow us to support
- headerless notifications of 1-3 lines (where each line is 20dp tall) where the 1-line
- variant is 56dp and the 2- and 3-line variants are both 76dp.
- -->
- <FrameLayout
- android:id="@+id/notification_headerless_margin_extra_top"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_headerless_margin_extra"
- android:layout_weight="1"
- />
-
<!-- extends ViewGroup -->
<NotificationTopLineView
android:id="@+id/notification_top_line"
@@ -153,12 +138,20 @@
android:orientation="vertical"
>
- <include
- layout="@layout/notification_template_text"
+ <com.android.internal.widget.NotificationVanishingFrameLayout
android:layout_width="match_parent"
android:layout_height="@dimen/notification_headerless_line_height"
- android:layout_marginTop="0dp"
- />
+ >
+ <!-- This is the simplest way to keep this text vertically centered without using
+ gravity="center_vertical" which causes jumpiness in expansion animations. -->
+ <include
+ layout="@layout/notification_template_text"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_text_height"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="0dp"
+ />
+ </com.android.internal.widget.NotificationVanishingFrameLayout>
<include
layout="@layout/notification_template_progress"
@@ -168,21 +161,6 @@
</LinearLayout>
- <!--
- This invisible FrameLayout is here as a collapsible padding. Having a layout_weight=1 is
- what causes this view (and it's counterpart at the opposite end) to collapse before the
- actual content views do.
- This pair of 10dp collapsible paddings (plus the 16dp fixed margins) allow us to support
- headerless notifications of 1-3 lines (where each line is 20dp tall) where the 1-line
- variant is 56dp and the 2- and 3-line variants are both 76dp.
- -->
- <FrameLayout
- android:id="@+id/notification_headerless_margin_extra_bottom"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_headerless_margin_extra"
- android:layout_weight="1"
- />
-
</LinearLayout>
</com.android.internal.widget.NotificationMaxHeightFrameLayout>
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index 513da5e..e6d724f 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -21,14 +21,16 @@
android:orientation="vertical">
<View android:id="@+id/splashscreen_icon_view"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center"/>
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:contentDescription="@string/splash_screen_view_icon_description"/>
<View android:id="@+id/splashscreen_branding_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal|bottom"
- android:layout_marginBottom="60dp"/>
+ android:layout_marginBottom="60dp"
+ android:contentDescription="@string/splash_screen_view_branding_description"/>
</android.window.SplashScreenView>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index aa4baf3..4b591bf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Kan nie meer gesig herken nie. Probeer weer."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Te eenders. Verander asseblief jou pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai jou kop \'n bietjie minder."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Draai jou kop \'n bietjie minder."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai jou kop \'n bietjie minder."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Verwyder enigiets wat jou gesig versteek."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Maak die bokant van jou skerm skoon, insluitend die swart balk"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gebruik kortpad"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Kleuromkering"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurkorreksie"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Verminder helderheid"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is afgeskakel"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-versoek is na video-oproep toe verander"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-versoek is na USSD-versoek toe verander"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Na nuwe SS-versoek toe verander"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Uitvissingwaarskuwing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Werkprofiel"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Kennisgewing gegee"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Vou uit"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Skakel aan"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorprivaatheid"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9b11350..a43b29a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ከእንግዲህ ፊትን ለይቶ ማወቅ አይችልም። እንደገና ይሞክሩ።"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"በጣም ይመሳሰላል፣ እባክዎ የእርስዎን ፎቶ አነሳስ ይለውጡ"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"የእርስዎን ፊት የሚደብቀውን ሁሉንም ነገር በማስወገድ ላይ"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"የማያ ገጽዎን አናት ያጽዱት፣ ጥቁር አሞሌውን ጨምሮ"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"አቋራጭ ይጠቀሙ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ተቃራኒ ቀለም"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"የቀለም ማስተካከያ"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ብሩህነትን ይቀንሱ"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> በርቷል።"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ጠፍተዋል።"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"የSS ጥያቄ ወደ የቪዲዮ ጥሪ ተለውጧል"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"የSS ጥያቄ ወደ የUSSD ጥያቄ ተለውጧል"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ወደ አዲስ የSS ጥያቄ ተለውጧል"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"የማስገር ማንቂያ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"የስራ መገለጫ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ነቅተዋል"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ዘርጋ"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ለመቀጠል፣ <b><xliff:g id="APP">%s</xliff:g></b> የመሣሪያዎን ካሜራ መድረስ ይፈልጋል።"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"አብራ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ዳሳሽ ግላዊነት"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bbf30fe..3990bab 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -618,7 +618,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"لم يعُد يمكن التعرّف على الوجه. حاول مرة أخرى."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"الوجه مشابه جدًا، يُرجى تغيير وضعيتك."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"حرّك رأسك قليلاً نحو الأمام مباشرة."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"حرّك رأسك قليلاً نحو الأمام مباشرة."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"حرّك رأسك قليلاً نحو الوسط."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"عليك بإزالة أي شيء يُخفي وجهك."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"يُرجى تنظيف الجزء العلوي من الشاشة، بما في ذلك الشريط الأسود."</string>
@@ -1755,7 +1756,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"استخدام الاختصار"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"قلب الألوان"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"تصحيح الألوان"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"تقليل السطوع"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم تفعيل <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم إيقاف <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1995,8 +1997,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"تم تغيير طلب SS إلى مكالمة فيديو."</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"تم تغيير طلب SS إلى طلب USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"تم التغيير إلى طلب SS الجديد."</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"تنبيه بشأن تصيّد احتيالي"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"الملف الشخصي للعمل"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"تمّ تفعيل التنبيه"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"توسيع"</string>
@@ -2356,4 +2357,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"للمتابعة، يحتاج تطبيق <b><xliff:g id="APP">%s</xliff:g></b> إلى الوصول إلى كاميرا الجهاز."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"تفعيل"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"الخصوصية في جهاز الاستشعار"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e4f657f..28af8a3 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"মুখমণ্ডল আৰু চিনাক্ত কৰিব নোৱাৰি। আকৌ চেষ্টা কৰক।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"একে ধৰণৰ হৈছে, অনুগ্ৰহ কৰি আপোনাৰ প’জটো সলনি কৰক।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"আপোনাৰ মুখখন ঢাকি ৰখা বস্তুবোৰ আঁতৰাওক।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ক’লা বাৰডালকে ধৰি আপোনাৰ স্ক্রীণৰ ওপৰৰ অংশ চাফা কৰক"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শ্বৰ্টকাট ব্যৱহাৰ কৰক"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ৰং বিপৰীতকৰণ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ৰং শুধৰণী"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"উজ্জ্বলতা কমাওক"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কীসমূহ ধৰি ৰাখক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধৰি ৰাখিছিল। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অফ কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"অব্যাহত ৰাখিবলৈ <b><xliff:g id="APP">%s</xliff:g></b>এ আপোনাৰ ডিভাইচৰ কেমেৰা এক্সেছ কৰাৰ আৱশ্যক।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"অন কৰক"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ছেন্সৰ সম্পৰ্কীয় গোপনীয়তাৰ নীতি"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 549784d..8459403 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Üzü artıq tanımaq olmur. Yenidən cəhd edin."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Digəri ilə oxşardır, pozanızı dəyişin."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı bir az döndərin."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Başınızı bir az döndərin."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı bir az döndərin."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Üzünüzü gizlədən maneələri kənarlaşdırın."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Qara panel daxil olmaqla, ekranın yuxarısını təmizləyin"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Qısayol İstifadə edin"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Rəng İnversiyası"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Rəng korreksiyası"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Parlaqlığı Azaldın"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Səs səviyyəsi düymələrinə basıb saxlayın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiv edildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Səs səviyyəsi düymələrinə basılaraq saxlanıb. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> deaktiv edilib."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS sorğusu video zəngə dəyişdirildi"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS sorğusu USSD sorğusuna dəyişdirildi"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Yeni SS sorğusuna dəyişdirildi"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Fişinq siqnalı"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"İş profili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Xəbərdarlıq edildi"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Genişləndirin"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Aktiv edin"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor Məxfiliyi"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 5709e3d..a7f6433 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -609,7 +609,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Više ne može da se prepozna lice. Probajte ponovo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše je slično, promenite pozu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje pomerite glavu."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malo manje pomerite glavu."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje pomerite glavu."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zaklanja lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite gornji deo ekrana, uključujući crnu traku"</string>
@@ -1689,7 +1690,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boja"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjite osvetljenost"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> zahteva pristup kameri uređaja radi nastavljanja."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 880c986..1022cef 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Не ўдаецца распазнаць твар. Паўтарыце спробу."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Не бачна розніцы. Памяняйце позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Вы занадта моцна павярнулі галаву."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Галава не ў цэнтры."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Вы занадта моцна павярнулі галаву."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Прыміце ўсё, што закрывае ваш твар."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Ачысціце ад бруду верхнюю частку экрана, у тым ліку чорную панэль"</string>
@@ -793,7 +794,7 @@
<string name="eventTypeAnniversary" msgid="4684702412407916888">"Гадавіна"</string>
<string name="eventTypeOther" msgid="530671238533887997">"Іншае"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"Карыстальніцкая"</string>
- <string name="emailTypeHome" msgid="1597116303154775999">"Хатні"</string>
+ <string name="emailTypeHome" msgid="1597116303154775999">"Асабістая"</string>
<string name="emailTypeWork" msgid="2020095414401882111">"Працоўная"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"Іншая"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"Мабільны"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Выкарыстоўваць камбінацыю хуткага доступу"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Інверсія колеру"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Карэкцыя колеру"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Паменшыць яркасць"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Клавішы гучнасці ўтрымліваліся націснутымі. Уключана служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Клавішы гучнасці ўтрымліваліся націснутымі. Служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" выключана."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-запыт заменены на відэавыклік"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-запыт заменены на USSD-запыт"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Зроблена замена на новы SS-запыт"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Абвестка пра фішынг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Працоўны профіль"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"З гукам"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Разгарнуць"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Каб працягнуць, дайце праграме <b><xliff:g id="APP">%s</xliff:g></b> доступ да камеры прылады."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Уключыць"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Прыватнасць інфармацыі з датчыка"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2ed363f..ef20bad 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Лицето не бе разпознато. Опитайте отново."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Позата ви е сходна с предишна. Моля, променете я."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не завъртайте главата си толкова много."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Не завъртайте главата си толкова много."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не завъртайте главата си толкова много."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Премахнете всичко, което закрива лицето ви."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Почистете горната част на екрана си, включително черната лента"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Използване на пряк път"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инвертиране на цветовете"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Коригиране на цветовете"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Намаляване на яркостта"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е изключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"За да продължите, <b><xliff:g id="APP">%s</xliff:g></b> се нуждае от достъп до камерата на устройството ви."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Включване"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Поверителност на сензорните данни"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index dd38e9a..0e30c04 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"আর মুখ চিনতে পারবেন না। আবার চেষ্টা করুন।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"একই ধরনের দেখতে, একটু অন্যদিকে ঘুরে দাঁড়ান।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপনার মাথাটি নিচের দিকে সামান্য নামান।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"আপনার মাথাটি নিচের দিকে সামান্য নামান।"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপনার মাথাটি সামান্য ঘোরান।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"আপনার ফেসকে আড়াল করে এমন সব কিছু সরিয়ে দিন।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ব্ল্যাক বার সহ আপনার স্ক্রিনের উপরের অংশ মুছে ফেলুন"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শর্টকাট ব্যবহার করুন"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"রঙ উল্টানো"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"রঙ সংশোধন"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"উজ্জ্বলতা কমান"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> চালু করা হয়েছে।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> বন্ধ করা হয়েছে।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS অনুরোধ ভিডিও কলে পরিবর্তন করা হয়েছে"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS অনুরোধ USSD অনুরোধে পরিবর্তন করা হয়েছে"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"নতুন SS অনুরোধে পরিবর্তন করা হয়েছে"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ফিশিংয়ের সতর্কতা"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"কর্মস্থলের প্রোফাইল"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"সতর্ক করা হয়েছে"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"বড় করুন"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"চালিয়ে যেতে, <b><xliff:g id="APP">%s</xliff:g></b> আপনার ডিভাইসের ক্যামেরা অ্যাক্সেস করতে চায়।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"চালু করুন"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"সেন্সর গোপনীয়তা"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index d5b10d5..77b64b5 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -609,7 +609,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Više nije moguće prepoznati lice. Pokušajte opet."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite položaj."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje zakrenite glavu."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malo manje zakrenite glavu."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje zakrenite glavu."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite prepreke koje blokiraju vaše lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh ekrana, uključujući crnu traku"</string>
@@ -689,7 +690,7 @@
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"pokrenuti korištenje odobrenja za pregled"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Dozvoljava vlasniku da pokrene korištenje odobrenja za aplikaciju. Ne bi trebalo biti potrebno za obične aplikacije."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora velikom brzinom uzorkovanja"</string>
- <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Dozvoljava aplikaciji da uzorkuje podatke senzora većom brzinom od 200 Hz"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Dozvoljava aplikaciji da uzorkuje podatke senzora brzinom većom od 200 Hz"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Postavljanje pravila za lozinke"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrolira dužinu i znakove koji su dozvoljeni u lozinkama za zaključavanje ekrana i PIN-ovima."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"Prati pokušaje otključavanja ekrana"</string>
@@ -1689,7 +1690,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Ispravka boja"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjenje osvjetljenja"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 280fe1a..a226ac3 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"És massa semblant; canvia de postura."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"No giris tant el cap."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"No inclinis tant el cap."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No giris tant el cap."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Suprimeix qualsevol cosa que amagui la teva cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Neteja la part superior de la pantalla, inclosa la barra negra"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilitza la drecera"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversió de colors"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correcció de color"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducció de la brillantor"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S\'han mantingut premudes les tecles de volum. S\'ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S\'han mantingut premudes les tecles de volum. S\'ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Activa"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privadesa dels sensors"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 091ed83..fdb2ff1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Obličej už nelze rozpoznat. Zkuste to znovu."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Příliš podobné, změňte výraz."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Natočte hlavu o něco méně."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Natočte hlavu o něco méně."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Natočte hlavu o něco méně."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Odstraňte vše, co vám zakrývá obličej."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistěte horní část obrazovky včetně černé části"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použít zkratku"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Převrácení barev"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Oprava barev"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Snížit jas"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Požadavek SS byl změněn na videohovor"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Požadavek SS byl změněn na požadavek USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Změněno na nový požadavek SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozornění na phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Pracovní profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozorněno"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozbalit"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Zapnout"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ochrana soukromí – senzor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 8e19100..dddc070 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -608,7 +608,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ansigtet kan ikke længere genkendes. Prøv igen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Det minder for meget om et andet. Skift stilling."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Du skal ikke dreje hovedet så meget."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Du skal ikke dreje hovedet så meget."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Du skal ikke dreje hovedet så meget."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hvis noget skjuler dit ansigt, skal du fjerne det."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengør toppen af din skærm, inkl. den sorte bjælke"</string>
@@ -1669,7 +1670,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Brug genvej"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ombytning af farver"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korriger farve"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducer lysstyrken"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er aktiveret."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er deaktiveret."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1873,8 +1875,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-anmodningen blev ændret til et videoopkald"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-anmodningen blev ændret til en USSD-anmodning"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Ændret til en SS-anmodning"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishingadvarsel"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbejdsprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Underrettet"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Udvid"</string>
@@ -2222,4 +2223,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<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_dialog_turn_on_button" msgid="7921147002346108119">"Aktivér"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Beskyttelse af sensoroplysninger"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d9710e6..472f1d2 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Gesicht wird nicht mehr erkannt. Erneut versuchen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Zu ähnlich. Bitte dreh deinen Kopf etwas."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Dreh den Kopf etwas weniger zur Seite."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Neig den Kopf etwas weniger stark."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Neig den Kopf etwas weniger stark."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Entferne alles, was dein Gesicht verdeckt."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinige den oberen Teil deines Bildschirms, einschließlich der schwarzen Leiste"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Verknüpfung verwenden"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Farbumkehr"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Farbkorrektur"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Helligkeit verringern"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist aktiviert."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist deaktiviert."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Zum Fortfahren benötigt <b><xliff:g id="APP">%s</xliff:g></b> Zugriff auf die Kamera deines Geräts."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivieren"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Datenschutz für Sensoren"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 358a1f1..22b3401 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Αδύνατη η αναγνώριση του προσώπου. Επανάληψη."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Πολύ παρόμοιο, αλλάξτε την πόζα σας."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Στρέψτε λιγότερο το κεφάλι σας."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Στρέψτε λιγότερο το κεφάλι σας."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Στρέψτε λιγότερο το κεφάλι σας."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Απομακρύνετε οτιδήποτε κρύβει το πρόσωπό σας."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Καθαρίστε το επάνω μέρος της οθόνης σας, συμπεριλαμβανομένης της μαύρης γραμμής"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Χρήση συντόμευσης"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Αντιστροφή χρωμάτων"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Διόρθωση χρωμάτων"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Μείωση φωτεινότητας"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ενεργοποιήθηκε."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>: απενεργοποιημένο"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Το αίτημα SS τροποποιήθηκε σε βιντεοκλήση"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Το αίτημα SS τροποποιήθηκε σε αίτημα USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Τροποποιήθηκε σε νέο αίτημα SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Ειδοποίηση ηλεκτρονικού ψαρέματος (phishing)"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Προφίλ εργασίας"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ειδοποιήθηκε"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Ανάπτυξη"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Για να συνεχίσετε, η εφαρμογή <b><xliff:g id="APP">%s</xliff:g></b> χρειάζεται πρόσβαση στην κάμερα της συσκευής σας."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ενεργοποίηση"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Απόρρητο αισθητήρα"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 058ae77..f2cbb75 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -606,7 +606,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index d91b3d0..f440c8a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -606,7 +606,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Colour inversion"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 60950ee..93881e9 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -606,7 +606,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 1915d45..a7fa30e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -606,7 +606,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Color correction"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 0a90aeac..ce9a915 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -606,7 +606,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognize face. Try again."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Color Inversion"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Color Correction"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor Privacy"</string>
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index e81d6d1..01d0c7e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ya no se reconoce el rostro. Vuelve a intentarlo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Es muy similar a la anterior. Haz otra pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Gira la cabeza un poco menos."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira la cabeza un poco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Quítate cualquier objeto que te cubra el rostro."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra negra"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar acceso directo"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir el brillo"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Como mantuviste presionadas las teclas de volumen, se activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se presionaron las teclas de volumen. Se desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Se cambió la solicitud SS por una videollamada"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Se cambió la solicitud SS por una solicitud USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Se cambió a una nueva solicitud SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de suplantación de identidad (phishing)"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabajo"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerta enviada"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidad del sensor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 70cac4a..28ff5fb 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"No puede reconocer tu cara. Vuelve a intentarlo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Se parece mucha a la anterior. Pon otra cara."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Gira la cabeza un poco menos."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No gires tanto la cabeza."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retira cualquier objeto que te tape la cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra de color negro"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar acceso directo"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir brillo"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, se ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se han mantenido pulsadas las teclas de volumen. Se ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Se ha cambiado la solicitud de SS a una videollamada"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Se ha cambiado la solicitud de SS a una solicitud de USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Se ha cambiado a una nueva solicitud de SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabajo"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Con sonido"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Mostrar"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidad del sensor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 2a2db3a..cb2bcdc 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nägu ei õnnestu enam tuvastada. Proovige uuesti."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Liiga sarnane, palun muutke oma asendit."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pöörake oma pead veidi vähem."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Pöörake oma pead veidi vähem."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pöörake oma pead veidi vähem."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Eemaldage kõik, mis varjab teie nägu."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhastage ekraani ülaosa, sh musta värvi riba"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kasuta otseteed"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Värvide ümberpööramine"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Värvide korrigeerimine"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Ereduse vähendamine"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-taotlus muudeti videokõneks"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-taotlus muudeti USSD-taotluseks"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Muudeti uueks SS-taotluseks"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Andmepüügihoiatus"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Tööprofiil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Teavitatud"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Laienda"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Lülita sisse"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Anduri privaatsus"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 901d8661..f95c279 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -451,7 +451,7 @@
<string name="permdesc_camera" msgid="5240801376168647151">"Aplikazioak abian den bitartean erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string>
<string name="permlab_backgroundCamera" msgid="7549917926079731681">"Argazkiak atera eta bideoak grabatu atzeko planoan."</string>
<string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Aplikazioak edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string>
- <string name="permlab_systemCamera" msgid="3642917457796210580">"onartu aplikazio edo zerbitzu bati sistemako kamerak atzitzea argazkiak eta bideoak ateratzeko"</string>
+ <string name="permlab_systemCamera" msgid="3642917457796210580">"eman sistemako kamerak atzitzeko baimena aplikazio edo zerbitzu bati argazkiak ateratzeko eta bideoak grabatzeko"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Pribilegioa duen edo sistemakoa den aplikazio honek edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko. Halaber, android.permission.CAMERA baimena izan behar du aplikazioak."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"eman jakinarazpenak jasotzeko baimena aplikazioari edo zerbitzuari kamerak ireki edo ixten direnean."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Kamera ireki edo itxi dela (eta zer aplikaziorekin) dioten jakinarazpenak jaso ditzake aplikazio honek."</string>
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ez dugu ezagutzen aurpegi hori. Saiatu berriro."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Jarrera berdintsuegia da. Alda ezazu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Biratu burua pixka bat gutxiago."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Biratu burua pixka bat gutxiago."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Biratu burua pixka bat gutxiago."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Kendu aurpegia estaltzen dizuten gauzak."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Garbitu pantailaren goialdea, barra beltza barne"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Erabili lasterbidea"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Koloreen alderantzikatzea"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Koloreen zuzenketa"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Murriztu distira"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu egin da."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu egin da."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bi bolumen-botoiak hiru segundoz"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Aktibatu"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sentsoreen pribatutasuna"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ec195e5..714b5e4 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"دیگر چهره را تشخیص نمیدهد. دوباره امتحان کنید."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"بسیار شبیه قبلی است، لطفاً قیافه دیگری بگیرید."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی صاف بگیرید."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"سرتان را کمی صاف بگیرید."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی صاف بگیرید."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"هرچیزی را که حائل چهرهتان است بردارید."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"بالای صفحه و همچنین نوار مشکی را تمیز کنید."</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"استفاده از میانبر"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"وارونگی رنگ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"تصحیح رنگ"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"کاهش روشنایی"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> روشن شد."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> خاموش شد."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"درخواست SS به تماس تصویری تغییر کرد"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"درخواست SS به درخواست USSD تغییر کرد"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"به درخواست SS جدید تغییر کرد"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"هشدار رمزگیری"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"نمایه کاری"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"هشدار ارسال شد"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"بزرگ کردن"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"برای ادامه دادن، <b><xliff:g id="APP">%s</xliff:g></b> باید به دوربین دستگاه دسترسی داشته باشد."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"روشن کردن"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"حریمخصوصی حسگر"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 6773dde..ef872e9 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ei enää tunnista kasvoja. Yritä uudelleen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Liian samanlainen, vaihda asentoa."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Käännä päätä vähän vähemmän."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Käännä päätä vähän vähemmän."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Käännä päätä vähän vähemmän."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Poista esteet kasvojesi edestä."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhdista näytön yläreuna, mukaan lukien musta palkki"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Käytä pikanäppäintä"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Käänteiset värit"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Värinkorjaus"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Vähennä kirkkautta"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin päälle."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin pois päältä."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-pyyntö vaihdettu videopuheluksi"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-pyyntö vaihdettu USSD-pyynnöksi"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Vaihdettu uudeksi SS-pyynnöksi"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varoitus tietojenkalastelusta"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Työprofiili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Hälytti"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Laajenna"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Jotta voit jatkaa, <b><xliff:g id="APP">%s</xliff:g></b> tarvitsee pääsyn laitteesi kameraan."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Laita päälle"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Anturin tietosuoja"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 9c4f92a..7cc3160 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ce visage ne sera plus reconnu. Réessayez."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Trop similaire. Changez de pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins votre tête."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Tournez un peu moins votre tête."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins votre tête."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui pourrait couvrir votre visage."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez le haut de l\'écran, y compris la barre noire"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utiliser le raccourci"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Réduire la luminosité"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"La demande SS a été remplacée par une demande d\'appel vidéo"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"La demande SS a été remplacée par une demande USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"La demande a été remplacée par une nouvelle demande SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerte d\'hameçonnage"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil professionnel"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerté"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Développer"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Activer"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidentialité des capteurs"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 78af86f..a3c0bad 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Impossible de reconnaître le visage. Réessayez."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Ressemble à un visage existant, changez de pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins la tête."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Tournez un peu moins la tête."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins la tête."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui cache votre visage."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez la partie supérieure de l\'écran, y compris la barre noire"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utiliser le raccourci"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Réduire la luminosité"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Requête SS transformée en appel vidéo"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Requête SS transformée en requête USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Remplacement par une nouvelle requête SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerte de hameçonnage"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil professionnel"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerte envoyée"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Développer"</string>
@@ -2068,7 +2069,7 @@
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Retour"</string>
<string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Applications récentes"</string>
<string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Notifications"</string>
- <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Configuration rapide"</string>
+ <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Réglages rapides"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue Marche/Arrêt"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pour continuer, <b><xliff:g id="APP">%s</xliff:g></b> a besoin d\'accéder à l\'appareil photo de votre appareil."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activer"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidentialité du capteur"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 949e486..72a799e 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Xa non se pode recoñecer a cara. Téntao de novo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"É moi similar. Cambia a pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Xira a cabeza un pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Xira a cabeza un pouco menos."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Xira a cabeza un pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Quita todo o que oculte a túa cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpa a parte superior da pantalla, incluída a barra de cor negra"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atallo"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de cor"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de cor"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir brillo"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume premidas. Activouse o servizo <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Desactivouse <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"A solicitude SS transformouse nunha videochamada"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"A solicitude SS transformouse nunha solicitude USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Transformouse nunha nova solicitude SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de traballo"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Con son"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Despregar"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b> precisa acceder á cámara do dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 29ce76b..7a2527f 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ચહેરો ઓળખી શકાતો નથી. ફરી પ્રયાસ કરો."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ઘણી સમાનતા ધરાવે છે, કૃપા કરીને તમારો પોઝ બદલો."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"તમારું માથું થોડું ફેરવો."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"તમારું માથું થોડું ફેરવો."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"તમારું માથું થોડું ઓછું ફેરવો."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"તમારા ચહેરાને છુપાવતી કંઈપણ વસ્તુ દૂર કરો."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"કાળી પટ્ટી સહિત, તમારી સ્ક્રીનની ટોચ સાફ કરો"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"શૉર્ટકટનો ઉપયોગ કરો"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"વિપરીત રંગમાં બદલવું"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"રંગ સુધારણા"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"બ્રાઇટનેસ ઘટાડો"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS વિનંતીને વીડિઓ કૉલમાં બદલવામાં આવી છે"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS વિનંતીને USSD વિનંતીમાં બદલવામાં આવી છે"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"નવી SS વિનંતીમાં બદલવામાં આવી છે"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ફિશિંગ અલર્ટ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ઑફિસની પ્રોફાઇલ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"અલર્ટ કરેલ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"વિસ્તૃત કરો"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ચાલુ રાખવા માટે, <b><xliff:g id="APP">%s</xliff:g></b>ને તમારા ડિવાઇસના કૅમેરાના ઍક્સેસની જરૂર છે."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ચાલુ કરો"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"સેન્સર પ્રાઇવસી સંબંધિત નોટિફિકેશન"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 15bb461..f108aa7 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"अब चेहरे की पहचान नहीं कर पा रहा. फिर से कोशिश करें."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"चेहरा काफ़ी मिलता-जुलता है, कृपया अपना पोज़ बदलें."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"अपना सिर थोड़ा कम घुमाएं."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"अपना सिर थोड़ा कम घुमाएं."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"अपना सिर थोड़ा कम घुमाएं."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"आपके चेहरे को छिपाने वाली सभी चीज़ों को हटाएं."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"अपनी स्क्रीन के सबसे ऊपरी हिस्से को साफ़ करें, जिसमें काले रंग वाला बार भी शामिल है"</string>
@@ -685,7 +686,7 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ऐप को परेशान न करें कॉन्फ़िगरेशन पढ़ने और लिखने देती है."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"देखने की अनुमतियां चालू करें"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"इस्तेमाल करने वाले को किसी ऐप्लिकेशन के लिए अनुमतियों का इस्तेमाल शुरू करने देता है. सामान्य ऐप्लिकेशन के लिए इसकी ज़रूरत कभी नहीं पड़ती."</string>
- <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"सेंसर डेटा को नमूने लेने की तेज़ दर पर ऐक्सेस करें"</string>
+ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"सेंसर डेटा को, नमूने लेने की तेज़ दर पर ऐक्सेस करें"</string>
<string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"यह अनुमति मिलने पर ऐप्लिकेशन, 200 हर्ट्ज़ से ज़्यादा की दर पर सेंसर डेटा का नमूना ले पाएगा"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियम सेट करना"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रीन लॉक पासवर्ड और पिन की लंबाई और उनमें स्वीकृत वर्णों को नियंत्रित करना."</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"शॉर्टकट का उपयोग करें"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"रंग बदलने की सुविधा"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"रंग में सुधार करने की सुविधा"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"स्क्रीन की चमक कम करें"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू कर दिया गया."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद कर दिया गया."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"जारी रखने के लिए, <b><xliff:g id="APP">%s</xliff:g></b> को आपके डिवाइस का कैमरा ऐक्सेस करने की ज़रूरत है."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"चालू करें"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेंसर से जुड़ी निजता के बारे में सूचना"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6e7c330..91073d4 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -609,7 +609,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Lice nije prepoznato. Pokušajte ponovo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite pozu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nagnite glavu malo manje."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Nagnite glavu malo manje."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nagnite glavu malo manje."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zakriva lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh zaslona, uključujući crnu traku"</string>
@@ -1689,7 +1690,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Upotrijebi prečac"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boje"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjenje svjetline"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za glasnoću. Uključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za glasnoću. Isključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index d966249..32f33df 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Már nem lehet felismerni az arcát. Próbálja újra."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Túlságosan hasonló, változtasson a pózon."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Kicsit kevésbé fordítsa el a fejét."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Kicsit kevésbé fordítsa el a fejét."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Kicsit kevésbé fordítsa el a fejét."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Távolítson el mindent, ami takarja az arcát."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Tisztítsa meg a képernyő tetejét, a fekete sávot is beleértve."</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Billentyűparancs használata"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Színek invertálása"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Színkorrekció"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Fényerő csökkentése"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bekapcsolva."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kikapcsolva."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Az SS-kérés módosítva videohívásra"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Az SS-kérés módosítva USSD-kérésre"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Új SS-kérésre módosítva"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Adathalászati figyelmeztetés"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Munkaprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Értesítve"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Kibontás"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Bekapcsolás"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Érzékelőkkel kapcsolatos adatvédelem"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 6110be3..cd1bbb1 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Չհաջողվեց ճանաչել դեմքը։ Նորից փորձեք:"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Շատ նման է նախորդին։ Փոխեք ձեր դիրքը։"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Գլուխն ուղիղ պահեք։"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Գլուխն ուղիղ պահեք։"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Գլուխն ուղիղ պահեք։"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Հեռացրեք այն ամենը, ինչը թաքցնում է ձեր երեսը:"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Մաքրեք էկրանի վերևի մասը, ներառյալ սև գոտին"</string>
@@ -686,7 +687,7 @@
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"թույլտվությունների մասին տվյալների հասանելիություն"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Հավելվածին հասանելի կդառնան թույլտվությունների մասին տվյալները։ Այս թույլտվությունն անհրաժեշտ չէ սովորական հավելվածներին։"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"օգտագործել սենսորների տվյալները բարձր հաճախականության վրա"</string>
- <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Թույլ է տալիս հավելվածին փորձել սենսորների տվյալները 200 Հց-ից ավել հաճախականության վրա"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Թույլ է տալիս հավելվածին փորձել սենսորների տվյալները 200 Հց-ից բարձր հաճախականության վրա"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Սահմանել գաղտնաբառի կանոնները"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Կառավարել էկրանի ապակողպման գաղտնաբառերի և PIN կոդերի թույլատրելի երկարությունն ու գրանշանները:"</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Օգտագործել դյուրանցումը"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Գունաշրջում"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Գունաշտկում"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Նվազեցնել պայծառությունը"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը միացավ։"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունն անջատվեց։"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS հարցումը փոխվել է տեսազանգի"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS հարցումը փոխվել է USSD հարցման"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Փոխվել է նոր SS հարցման"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Ֆիշինգի մասին զգուշացում"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Աշխատանքային պրոֆիլ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ուղարկվել է զգուշացում"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Ընդարձակել"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Շարունակելու համար <b><xliff:g id="APP">%s</xliff:g></b> հավելվածին անհրաժեշտ է ձեր սարքի տեսախցիկի օգտագործման թույլտվություն։"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Միացնել"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Տվիչների գաղտնիություն"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3335f59..f7fe384 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengenali wajah. Coba lagi."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu mirip, ubah pose Anda."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Putar sedikit kepala Anda."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Putar sedikit kepala Anda."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Putar sedikit kepala Anda."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Singkirkan apa saja yang menutupi wajah Anda."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bagian atas layar, termasuk kotak hitam"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversi Warna"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Koreksi Warna"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Kurangi Kecerahan"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> diaktifkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dinonaktifkan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Permintaan SS diubah ke panggilan video"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Permintaan SS diubah ke permintaan USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Diubah ke permintaan SS baru"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Peringatan phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil kerja"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Diingatkan"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Luaskan"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Untuk melanjutkan, <b><xliff:g id="APP">%s</xliff:g></b> memerlukan akses ke kamera perangkat."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktifkan"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privasi Sensor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 86a4638..5824c3a6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Andlit þekkist ekki lengur. Reyndu aftur."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Of svipað. Stilltu þér öðruvísi upp."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Snúðu höfðinu aðeins minna."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Hallaðu höfðinu aðeins minna."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Snúðu höfðinu aðeins minna."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Fjarlægðu það sem kann að hylja andlitið."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hreinsaðu efsta hluta skjásins þíns, þ.m.t. svörtu stikuna"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Nota flýtileið"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Umsnúningur lita"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Litaleiðrétting"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Draga úr birtu"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Hljóðstyrkstökkum haldið inni. Kveikt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Hljóðstyrkstökkum haldið inni. Slökkt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-beiðni breytt í myndsímtal"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-beiðni breytt í USSD-beiðni"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Breytt í nýja SS-beiðni"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Viðvörun um vefveiðar"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Vinnusnið"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Tilkynnt"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Stækka"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Kveikja"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Persónuvernd skynjara"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index fa6b461..d435a25 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Non è più possibile riconoscere il volto. Riprova."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Troppo simile; cambia posa."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira un po\' meno la testa."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Gira un po\' meno la testa."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira un po\' meno la testa."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Rimuovi tutto ciò che ti nasconde il viso."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pulisci la parte superiore dello schermo, inclusa la barra nera"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usa scorciatoia"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversione dei colori"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correzione del colore"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Riduci la luminosità"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> attivato."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> disattivato."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Richiesta SS modificata in videochiamata"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Richiesta SS modificata in richiesta USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Modificata in nuova richiesta SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Allerta phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profilo di lavoro"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Avviso inviato"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Espandi"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Attiva"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacy relativa ai sensori"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d9b889e..ee771df 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"כבר לא ניתן לזהות פנים. יש לנסות שוב."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"דומה מדי, יש לשנות תנוחה."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"עליך ליישר קצת את הראש."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"עליך ליישר קצת את הראש."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"עליך ליישר קצת את הראש."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"יש להסיר כל דבר שמסתיר את הפנים."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"עליך לנקות את החלק העליון של המסך, כולל הסרגל השחור"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"השתמש בקיצור הדרך"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"היפוך צבעים"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"תיקון צבעים"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"הפחתה של עוצמת הבהירות"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"בקשת SS שונתה לשיחת וידאו"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"בקשת SS שונתה לבקשת USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"היה שינוי לבקשת SS חדשה"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"התראה על פישינג"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"פרופיל עבודה"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"נשלחה התראה"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"הרחב"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"כדי להמשיך, האפליקציה <b><xliff:g id="APP">%s</xliff:g></b> צריכה גישה למצלמה של המכשיר שלך."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"הפעלה"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"פרטיות חיישנים"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 68213def..b03f94c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -538,10 +538,10 @@
<string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"このアプリに画面ロックの複雑さレベル(高、中、低、なし)を認識することを許可します。複雑さレベルは、画面ロックの文字数の範囲やタイプを示すものです。アプリから一定レベルまで画面ロックを更新するよう推奨されることもありますが、ユーザーは無視したり別の操作を行ったりできます。画面ロックは平文で保存されないため、アプリが正確なパスワードを知ることはありません。"</string>
<string name="permlab_useBiometric" msgid="6314741124749633786">"生体認証ハードウェアの使用"</string>
<string name="permdesc_useBiometric" msgid="7502858732677143410">"生体認証ハードウェアを認証に使用することをアプリに許可します"</string>
- <string name="permlab_manageFingerprint" msgid="7432667156322821178">"指紋ハードウェアの管理"</string>
+ <string name="permlab_manageFingerprint" msgid="7432667156322821178">"指紋認証ハードウェアの管理"</string>
<string name="permdesc_manageFingerprint" msgid="2025616816437339865">"使用する指紋テンプレートの追加や削除を行う方法の呼び出しをアプリに許可します。"</string>
- <string name="permlab_useFingerprint" msgid="1001421069766751922">"指紋ハードウェアの使用"</string>
- <string name="permdesc_useFingerprint" msgid="412463055059323742">"指紋ハードウェアを認証に使用することをアプリに許可します"</string>
+ <string name="permlab_useFingerprint" msgid="1001421069766751922">"指紋認証ハードウェアの使用"</string>
+ <string name="permdesc_useFingerprint" msgid="412463055059323742">"指紋認証ハードウェアを認証に使用することをアプリに許可します"</string>
<string name="permlab_audioWrite" msgid="8501705294265669405">"音楽コレクションの変更"</string>
<string name="permdesc_audioWrite" msgid="8057399517013412431">"音楽コレクションの変更をアプリに許可します。"</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"動画コレクションの変更"</string>
@@ -567,7 +567,7 @@
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋認証を完了しました"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"顔を認証しました"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"顔を認証しました。[確認] を押してください"</string>
- <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"指紋ハードウェアは使用できません。"</string>
+ <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"指紋認証ハードウェアは使用できません。"</string>
<string name="fingerprint_error_no_space" msgid="6126456006769817485">"指紋を保存できません。既存の指紋を削除してください。"</string>
<string name="fingerprint_error_timeout" msgid="2946635815726054226">"指紋の読み取りがタイムアウトになりました。もう一度お試しください。"</string>
<string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋の操作をキャンセルしました。"</string>
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"顔を認識できなくなりました。もう一度お試しください。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"似すぎています。ポーズを変えてください。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"顔の向きを少し戻してください。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"顔の向きを少し戻してください。"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"顔の向きを少し戻してください。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"顔を隠しているものをすべて外してください"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"黒いバーを含め、画面の上部をきれいにしてください"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ショートカットを使用"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"色反転"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色補正"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"明るさを下げる"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が ON になりました。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が OFF になりました。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"続行するには、<b><xliff:g id="APP">%s</xliff:g></b> にデバイスのカメラへのアクセスを許可する必要があります。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ON にする"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"センサー プライバシー"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3c76454..c25bd57 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"სახის ამოცნობა ვეღარ ხერხდება. ცადეთ ხელახლა."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"მეტისმეტად მსგავსია. გთხოვთ, შეცვალოთ პოზა."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"მოაშორეთ ყველაფერი, რაც სახეს გიფარავთ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"გაწმინდეთ ეკრანის ზედა ნაწილი, შავი ზოლის ჩათვლით."</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"მალსახმობის გამოყენება"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ფერთა ინვერსია"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ფერთა კორექცია"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"სიკაშკაშის შემცირება"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ჩართულია."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> გამორთულია."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS მოთხოვნა შეიცვალა ვიდეოზარის მოთხოვნით"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS მოთხოვნა შეიცვალა USSD მოთხოვნით"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"შეიცვალა ახალი SS მოთხოვნით"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"გაფრთხილება ფიშინგის შესახებ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"სამსახურის პროფილი"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"გაფრთხილებით"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"გაშლა"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"გასაგრძელებლად <b><xliff:g id="APP">%s</xliff:g></b>-ს თქვენი მოწყობილობის კამერაზე წვდომა სჭირდება."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ჩართვა"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"სენსორის კონფიდენციალურობა"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 38f9475..68edfea 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Енді бет анықтау мүмкін емес. Әрекетті қайталаңыз."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Алдыңғысына тым ұқсас, басқаша қалыпта түсіңіз."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Басыңызды түзурек ұстаңыз."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Басыңызды түзурек ұстаңыз."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Басыңызды кішкене бұрыңыз."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Бетіңізді жауып тұрған нәрсені алып тастаңыз."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экранның жоғарғы жағын, сонымен қатар қара жолақты өшіріңіз."</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Төте жолды пайдалану"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Түстер инверсиясы"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Түсті түзету"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Жарықтығын азайту"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дыбыс деңгейі пернелерін басып тұрған соң, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өшірілді."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS сұрауы бейне қоңырауға өзгертілді"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS сұрауы USSD сұрауына өзгертілді"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Жаңа SS сұрауына өзгертілді"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг ескертуі"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Жұмыс профилі"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ескертілді"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Жаю"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Жалғастыру үшін <b><xliff:g id="APP">%s</xliff:g></b> қолданбасы құрылғыңыздың камерасына рұқсат алу керек."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Қосу"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Датчикке қатысты құпиялылық"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 5bde733..b3516d5 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"មិនអាចសម្គាល់មុខបានទៀតទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ស្រដៀងគ្នាពេក សូមផ្លាស់ប្ដូរកាយវិការរបស់អ្នក។"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ងាកក្បាលរបស់អ្នកតិចជាងមុនបន្តិច។"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ងាកក្បាលរបស់អ្នកតិចជាងមុនបន្តិច។"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ងាកក្បាលរបស់អ្នកបន្តិចទៀត។"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"យកអ្វីដែលបាំងមុខរបស់អ្នកចេញ។"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"សម្អាតផ្នែកខាងលើនៃអេក្រង់របស់អ្នក រួមទាំងរបារខ្មៅ"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ប្រើប្រាស់ផ្លូវកាត់"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"បញ្ច្រាសពណ៌"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ការកែពណ៌"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"បន្ថយពន្លឺ"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ចុចគ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ដើម្បីបន្ត <b><xliff:g id="APP">%s</xliff:g></b> ត្រូវការសិទ្ធិចូលប្រើកាមេរ៉ារបស់ឧបករណ៍អ្នក។"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"បើក"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ឯកជនភាពឧបករណ៍ចាប់សញ្ញា"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index cf0f644..22bdd77 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ಮುಖ ಗುರುತಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ತುಂಬಾ ಸಮಾನ, ನಿಮ್ಮ ಪೋಸ್ ಬದಲಾಯಿಸಿ."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಹೆಚ್ಚು ತಿರುಗಿಸಬೇಡಿ."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಹೆಚ್ಚು ತಿರುಗಿಸಬೇಡಿ."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಸ್ವಲ್ಪ ಕಡಿಮೆ ತಿರುಗಿಸಿ."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರೆಮಾಡುವ ಯಾವುದನ್ನಾದರೂ ತೆಗೆದುಹಾಕಿ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ಬ್ಲ್ಯಾಕ್ ಬಾರ್ ಸೇರಿದಂತೆ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಮೇಲ್ಭಾಗವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ಶಾರ್ಟ್ಕಟ್ ಬಳಸಿ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ಬಣ್ಣ ವಿಲೋಮ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಲಾಗಿದೆ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS ವಿನಂತಿಯನ್ನು ವೀಡಿಯೊ ಕರೆಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS ವಿನಂತಿಯನ್ನು USSD ವಿನಂತಿಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ಹೊಸ SS ವಿನಂತಿಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ಫಿಶಿಂಗ್ ಕುರಿತು ಎಚ್ಚರಿಕೆ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ಎಚ್ಚರಿಕೆ ನೀಡಲಾಗಿದೆ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ಮುಂದುವರಿಯಲು, <b><xliff:g id="APP">%s</xliff:g></b> ಗೆ ನಿಮ್ಮ ಸಾಧನದ ಕ್ಯಾಮರಾದ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ಆನ್ ಮಾಡಿ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ಸೆನ್ಸರ್ ಗೌಪ್ಯತೆ"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8fde34c..52f0a7c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"더 이상 얼굴을 인식할 수 없습니다. 다시 시도하세요."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"너무 비슷합니다. 다른 포즈를 취해 보세요."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"고개를 조금 덜 돌려 보세요."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"고개를 조금 덜 돌려 보세요."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"고개를 조금 덜 돌려 보세요."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"얼굴이 가려지지 않도록 해 주세요."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"검은색 바를 포함한 화면 상단을 청소하세요."</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"단축키 사용"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"색상 반전"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"색상 보정"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"밝기 낮추기"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS 요청이 화상 통화로 변경됨"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS 요청이 USSD 요청으로 변경됨"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"새 SS 요청으로 변경됨"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"피싱 알림"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"직장 프로필"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"알림 전송됨"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"펼치기"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"계속하려면 <b><xliff:g id="APP">%s</xliff:g></b>에서 기기 카메라에 액세스해야 합니다."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"사용"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"센서 개인정보 보호"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index aa5d01c..4d8888e 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Жүз таанылган жок. Кайталап көрүңүз."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Мурункуга окшош болуп калды, башкача туруңуз."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Башыңызды бир аз гана эңкейтиңиз."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Башыңызды бир аз гана эңкейтиңиз."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Башыңызды бир аз гана эңкейтиңиз."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Жүзүңүздү жашырып турган нерселерди алып салыңыз."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экраныңыздын жогору жагын, анын ичинде тилкени да тазалаңыз"</string>
@@ -1206,7 +1207,7 @@
<string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңыртууну издөө"</string>
<string name="smv_application" msgid="3775183542777792638">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу (<xliff:g id="PROCESS">%2$s</xliff:g> процесси) өз алдынча иштеткен StrictMode саясатын бузду."</string>
<string name="smv_process" msgid="1398801497130695446">"<xliff:g id="PROCESS">%1$s</xliff:g> процесси өзүнүн мажбурланган StrictMode саясатын бузуп койду."</string>
- <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Телефон жаңыртылууда…"</string>
+ <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Телефон жаңырууда…"</string>
<string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"Планшет жаңыртылууда…"</string>
<string name="android_upgrading_title" product="device" msgid="6774767702998149762">"Түзмөк жаңыртылууда…"</string>
<string name="android_start_title" product="default" msgid="4036708252778757652">"Телефон күйгүзүлүүдө…"</string>
@@ -1216,7 +1217,7 @@
<string name="android_upgrading_fstrim" msgid="3259087575528515329">"Сактагыч ыңгайлаштырылууда."</string>
<string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"Тутумду жаңыртуу аяктоодо…"</string>
<string name="app_upgrading_toast" msgid="1016267296049455585">"<xliff:g id="APPLICATION">%1$s</xliff:g> жаңыртылууда..."</string>
- <string name="android_upgrading_apk" msgid="1339564803894466737">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колдонмо ыңгайлаштырылууда."</string>
+ <string name="android_upgrading_apk" msgid="1339564803894466737">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колдонмо оптималдаштырылууда."</string>
<string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> даярдалууда."</string>
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Колдонмолорду иштетип баштоо"</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"Жүктөлүүдө"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Кыска жолду колдонуу"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Түстү инверсиялоо"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Түсүн тууралоо"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Экрандын жарыктыгын төмөндөтүү"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> күйгүзүлдү."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өчүрүлдү."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS сурамы видео чалууга өзгөртүлдү"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS сурамы USSD сурамына өзгөртүлдү"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Жаңы SS сурамына өзгөртүлдү"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг жөнүндө эскертүү"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Жумуш профили"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Эскертилди"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Жайып көрсөтүү"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Улантуу үчүн <b><xliff:g id="APP">%s</xliff:g></b> колдонмосуна түзмөгүңүздүн камерасын пайдаланууга уруксат беришиңиз керек."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Күйгүзүү"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Сенсордун купуялыгы"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 806a5e2..87c2ceb 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້ອີກຕໍ່ໄປ. ກະລຸນາລອງໃໝ່."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ຄ້າຍກັນເກີນໄປ, ກະລຸນາປ່ຽນທ່າຂອງທ່ານ."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ນຳສິ່ງທີ່ກີດຂວາງໃບໜ້າທ່ານອອກ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ທຳຄວາມສະອາດສ່ວນເທິງສຸດຂອງໜ້າຈໍທ່ານ, ຮວມທັງແຖບດຳນຳ"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ໃຊ້ປຸ່ມລັດ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ການປີ້ນສີ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ການແກ້ໄຂຄ່າສີ"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ຫຼຸດຄວາມສະຫວ່າງ"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ເປີດໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ປິດ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ໄວ້ແລ້ວ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ເພື່ອດຳເນີນການຕໍ່, <b><xliff:g id="APP">%s</xliff:g></b> ຕ້ອງການສິດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງອຸປະກອນທ່ານ."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ເປີດໃຊ້"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ຄວາມເປັນສ່ວນຕົວເຊັນເຊີ"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8f64bdd..2c3742b 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nebegalima atpažinti veido. Bandykite dar kartą."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Per daug panašu, pakeiskite veido išraišką."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nesukite tiek galvos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Nesukite tiek galvos."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nesukite tiek galvos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Patraukite viską, kas užstoja jūsų veidą."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Išvalykite ekrano viršų, įskaitant juodą juostą"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Naudoti spartųjį klavišą"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Spalvų inversija"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Spalvų taisymas"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Šviesumo mažinimas"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ įjungta."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ išjungta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS užklausa pakeista į vaizdo skambutį"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS užklausa pakeista į USSD užklausą"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Pakeista į naują SS užklausą"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Įspėjimas apie sukčiavimą"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Darbo profilis"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Įspėjimas išsiųstas"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Išskleisti"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Įjungti"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Jutiklių privatumas"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 346ade4..8d6ce86 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -609,7 +609,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Seju vairs nevar atpazīt. Mēģiniet vēlreiz."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Pārāk līdzīgi. Lūdzu, mainiet pozu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pagrieziet galvu nedaudz mazāk."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Pagrieziet galvu nedaudz mazāk."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pagrieziet galvu nedaudz mazāk."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Noņemiet visu, kas aizsedz jūsu seju."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Notīriet ekrāna augšdaļu, tostarp melno joslu."</string>
@@ -1689,7 +1690,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Izmantot saīsni"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Krāsu inversija"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Krāsu korekcija"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Spilgtuma samazināšana"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika ieslēgts."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika izslēgts."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma taustiņus un turiet tos trīs sekundes."</string>
@@ -1902,8 +1904,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS pieprasījums mainīts uz videozvanu"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS pieprasījums mainīts uz USSD pieprasījumu"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Mainīts uz jaunu SS pieprasījumu"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Brīdinājums par pikšķerēšanu"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Darba profils"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Brīdināts"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Izvērst"</string>
@@ -2254,4 +2255,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Ieslēgt"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensoru konfidencialitāte"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 8d176ad..af3ce00 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ликот не се препознава. Обидете се повторно."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Премногу слично, сменете ја позата."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не вртете ја главата толку многу."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Не вртете ја главата толку многу."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не вртете ја главата толку многу."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Отстранете ги работите што ви го покриваат лицето."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Исчистете го врвот на екранот, вклучувајќи ја црната лента"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Користи кратенка"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инверзија на бои"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Корекција на бои"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Намалете ја осветленоста"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е вклучена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е исклучена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Барањето SS е изменето во видео повик"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Барањето SS е изменето во барање USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Променето на ново барање SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Предупредување за фишинг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Работен профил"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Предупредено"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Прошири"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"За да продолжи, на <b><xliff:g id="APP">%s</xliff:g></b> ѝ е потребен пристап до камерата на уредот."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Вклучи"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Приватност на сензорот"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index fd61768..aaab7b5 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ഇനി മുഖം തിരിച്ചറിയാനാവില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"വളരെയധികം സമാനത, നിങ്ങളുടെ പോസ് മാറ്റുക."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"നിങ്ങളുടെ മുഖം മറയ്ക്കുന്നത് എല്ലാം നീക്കം ചെയ്യൂ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"കറുപ്പ് ബാർ ഉൾപ്പെടെ നിങ്ങളുടെ സ്ക്രീനിന്റെ മുകൾഭാഗം വൃത്തിയാക്കുക"</string>
@@ -685,10 +686,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"\'ശല്യപ്പെടുത്തരുത്\' കോൺഫിഗറേഷൻ വായിക്കുന്നതിനും എഴുതുന്നതിനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"അനുമതി ഉപയോഗം കാണാൻ ആരംഭിക്കുക"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ഒരു ആപ്പിനുള്ള അനുമതി ഉപയോഗം ആരംഭിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
- <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
- <skip />
- <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
- <skip />
+ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ഉയർന്ന സാംപ്ലിംഗ് റേറ്റിൽ സെൻസർ ഡാറ്റ ആക്സസ് ചെയ്യുക"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz-നേക്കാൾ ഉയർന്ന റേറ്റിൽ സെൻസർ ഡാറ്റ സാമ്പിൾ ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"പാസ്വേഡ് നിയമങ്ങൾ സജ്ജീകരിക്കുക"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"സ്ക്രീൻ ലോക്ക് പാസ്വേഡുകളിലും PIN-കളിലും അനുവദിച്ചിരിക്കുന്ന ദൈർഘ്യവും പ്രതീകങ്ങളും നിയന്ത്രിക്കുക."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"സ്ക്രീൻ അൺലോക്ക് ശ്രമങ്ങൾ നിരീക്ഷിക്കുക"</string>
@@ -1669,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"കുറുക്കുവഴി ഉപയോഗിക്കുക"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"വർണ്ണ വിപര്യയം"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"നിറം ക്രമീകരിക്കൽ"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"തെളിച്ചം കുറയ്ക്കുക"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"വോളിയം കീകൾ പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓണാക്കി."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"വോളിയം കീകൾ അമർത്തിപ്പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫാക്കി."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</string>
@@ -1873,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS അഭ്യർത്ഥന, വീഡിയോ കോളിലേക്ക് മാറ്റി"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS അഭ്യർത്ഥന, USSD അഭ്യർത്ഥനയിലേക്ക് മാറ്റി"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"പുതിയ SS അഭ്യർത്ഥനയിലേക്ക് മാറ്റി"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ഫിഷിംഗ് മുന്നറിയിപ്പ്"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"മുന്നറിയിപ്പ് നൽകി"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"വികസിപ്പിക്കുക"</string>
@@ -2222,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"തുടരാൻ, <b><xliff:g id="APP">%s</xliff:g></b> ആപ്പിന് നിങ്ങളുടെ ഉപകരണത്തിന്റെ ക്യാമറയിലേക്ക് ആക്സസ് നൽകേണ്ടതുണ്ട്."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ഓണാക്കുക"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"സെൻസർ സ്വകാര്യത"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index d5937d3..c699285 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Царайг таних боломжгүй боллоо. Дахин оролдоно уу."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Хэт адилхан байгаа тул байрлалаа өөрчилнө үү."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Толгойгоо арай багаар эргүүлнэ үү."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Толгойгоо арай багаар эргүүлнэ үү."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Толгойгоо арай багаар эргүүлнэ үү."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Таны нүүрийг далдалж буй аливаа зүйлийг хасна уу."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Хар хэсэг зэрэг дэлгэцийнхээ дээд хэсгийг цэвэрлэнэ үү"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Товчлол ашиглах"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Өнгө хувиргалт"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Өнгөний засвар"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Гэрэлтүүлгийг багасгах"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаалаа."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраалаа."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS хүсэлтийг видео дуудлага болгон өөрчилсөн"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS хүсэлтийг USSD хүсэлт болгон өөрчилсөн"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Шинэ SS хүсэлт болгон өөрчилсөн"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг сэрэмжлүүлэг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ажлын профайл"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Мэдэгдсэн"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Дэлгэх"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Үргэлжлүүлэхийн тулд <b><xliff:g id="APP">%s</xliff:g></b> таны төхөөрөмжийн камерт хандах шаардлагатай."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Асаах"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Мэдрэгчийн нууцлал"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 5f4d5fd..a31951a 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"एकाच प्रकारची पोझ देत आहात कृपया तुमची पोझ बदला."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"तुमचे डोके थोडे कमी फिरवा."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"तुमचे डोके थोडे कमी फिरवा."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"तुमचे डोके थोडे कमी फिरवा."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"तुमचा चहेरा लपवणारे काहीही काढून टाका."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ब्लॅक बार सह तुमच्या स्क्रीनची वरची बाजू साफ करा"</string>
@@ -685,10 +686,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"व्यत्यय आणू नका कॉंफिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी ॲपला अनुमती देते."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"व्ह्यू परवानगी वापर सुरू करा"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"धारकास अॅपसाठी परवानगी वापरणे सुरू करण्याची अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यकता नसते."</string>
- <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
- <skip />
- <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
- <skip />
+ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"उच्च नमुना दराने सेन्सर डेटा अॅक्सेस करते"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ॲपला २०० Hz पेक्षा जास्त दराने सेन्सर डेटाचा नमुना तयार करण्याची अनुमती देते"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियम सेट करा"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रीन लॉक पासवर्ड आणि पिन मध्ये अनुमती दिलेले लांबी आणि वर्ण नियंत्रित करा."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"स्क्रीन अनलॉक प्रयत्नांचे परीक्षण करा"</string>
@@ -1669,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"शॉर्टकट वापरा"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"रंगांची उलटापालट"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"रंग सुधारणा"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ब्राइटनेस कमी करा"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> सुरू केला आहे."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केले आहे."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string>
@@ -1873,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS विनंती व्हिडिओ कॉलवर बदलली"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS विनंती USSD विनंतीवर बदलली"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"नवीन SS विनंतीवर बदलली"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"फिशिंगशी संबंधित सूचना"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"कार्य प्रोफाईल"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"सूचना दिल्या"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"विस्तृत करा"</string>
@@ -2222,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"पुढे सुरू ठेवण्यासाठी, <b><xliff:g id="APP">%s</xliff:g></b> ला तुमच्या डिव्हाइसचा कॅमेरा अॅक्सेस करण्याची आवश्यकता आहे."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"सुरू करा"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेन्सरशी संबंधित गोपनीयतेबाबत सूचना"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 27b1d60..5e5b29f 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengecam wajah. Cuba lagi."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu serupa, sila ubah lagak gaya anda."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pusingkan kepala anda kurang sedikit."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Pusingkan kepala anda kurang sedikit."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pusingkan kepala anda kurang sedikit."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Alih keluar apa saja yang melindungi wajah anda."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bahagian atas skrin anda, termasuk bar hitam"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Penyongsangan Warna"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Pembetulan Warna"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Kurangkan Kecerahan"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dihidupkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dimatikan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Hidupkan"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privasi Penderia"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9e1bd73..137c138 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"မျက်နှာ မမှတ်သားနိုင်တော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ဆင်တူနေသည်၊ အမူအရာ ပြောင်းပါ။"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"သင့်မျက်နှာကို ကွယ်နေသည့်အရာအားလုံး ဖယ်ပါ။"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"အနက်ရောင်ဘားအပါအဝင် ဖန်သားပြင်ထိပ်ကို သန့်ရှင်းရေး လုပ်ပါ"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ဖြတ်လမ်းလင့်ခ်ကို သုံးရန်"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"အရောင် ပြောင်းပြန်လှန်ခြင်း"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"အရောင်ပြင်ဆင်ခြင်း"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"တောက်ပမှုကို လျှော့ခြင်း"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ဖွင့်လိုက်သည်။"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ပိတ်လိုက်သည်။"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ဆက်လက်လုပ်ဆောင်ရန် <b><xliff:g id="APP">%s</xliff:g></b> က သင့်စက်၏ ကင်မရာကို အသုံးပြုခွင့်ရရန် လိုအပ်သည်။"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ဖွင့်ရန်"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"အာရုံခံကိရိယာ လုံခြုံရေး"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c846701..de71c39 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Kan ikke gjenkjenne ansiktet lenger. Prøv igjen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"For likt – endre posituren din."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vri hodet ditt litt mindre."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Vri hodet ditt litt mindre."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vri hodet ditt litt mindre."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Fjern alt som skjuler ansiktet ditt."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengjør den øverste delen av skjermen, inkludert den svarte linjen"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Bruk snarveien"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Fargeinvertering"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Fargekorrigering"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduser lysstyrken"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått på."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått av."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-forespørsel endret til videoanrop"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-forespørsel endret til USSD-forespørsel"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Endret til ny SS-forespørsel"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varsel om nettfisking"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbeidsprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Varslet"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Vis"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"For å fortsette må <b><xliff:g id="APP">%s</xliff:g></b> ha tilgang til enhetskameraet."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Slå på"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorpersonvern"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 9af472a..83c03a4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"अब उप्रान्त अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"अनुहार उस्तै भयो, कृपया आफ्नो पोज बदल्नुहोस्।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"तपाईंको अनुहार लुकाउने सबै कुरा लुकाउनुहोस्।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"कालो रङको पट्टीलगायत आफ्नो स्क्रिनको माथिल्लो भाग सफा गर्नुहोस्"</string>
@@ -685,10 +686,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"बाधा नपुर्याउँनुहोस् कन्फिगरेसन पढ्न र लेख्नको लागि एपलाई अनुमति दिनुहोस्।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"हेर्ने अनुमतिको प्रयोग सुरु गर्नुहोस्"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"वाहकलाई कुनै एपसम्बन्धी अनुमतिको प्रयोग सुरु गर्न दिन्छ। साधारण एपहरूलाई कहिल्यै आवश्यक नपर्नु पर्ने हो।"</string>
- <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
- <skip />
- <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
- <skip />
+ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"नमुना लिने उच्च दरमा सेन्सरसम्बन्धी डेटा प्रयोग गर्ने"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"यो अनुमति दिइएमा एपले २०० हर्जभन्दा बढी दरमा सेन्सरसम्बन्धी डेटाको नमुना लिन सक्छ"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रिन लक पासवर्ड र PIN हरूमा अनुमति दिइएको लम्बाइ र वर्णहरूको नियन्त्रण गर्नुहोस्।"</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"मनिटरको स्क्रिन अनलक गर्ने प्रयासहरू"</string>
@@ -1669,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"सर्टकट प्रयोग गर्नुहोस्"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"रङ्ग उल्टाउने सुविधा"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"रङ्ग सच्याउने सुविधा"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"स्क्रिनको चमक घटाउनुहोस्"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन भयो।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अफ भयो।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</string>
@@ -1873,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS अनुरोधलाई भिडियो कलमा परिवर्तन गरियो"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS अनुरोधलाई USSD अनुरोधमा परिवर्तन गरियो"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"नयाँ SS अनुरोधमा परिवर्तन गरियो"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"फिसिङसम्बन्धी अलर्ट"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"कार्य प्रोफाइल"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"सतर्कता गरियो"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"विस्तृत गर्नुहोस्"</string>
@@ -2222,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"जारी राख्न <b><xliff:g id="APP">%s</xliff:g></b> लाई तपाईंको यन्त्रको क्यामेरा प्रयोग गर्ने अनुमति दिनु पर्ने हुन्छ।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"अन गर्नुहोस्"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेन्सरसम्बन्धी गोपनीयता"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 29f2b6f..4410e94 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -26,6 +26,10 @@
<color name="notification_default_color_dark">#ddffffff</color>
+ <color name="notification_primary_text_color_current">@color/notification_primary_text_color_dark</color>
+ <color name="notification_secondary_text_color_current">@color/notification_secondary_text_color_dark</color>
+ <color name="notification_default_color_current">@color/notification_default_color_dark</color>
+
<color name="chooser_row_divider">@color/list_divider_color_dark</color>
<color name="chooser_gradient_background">@color/loading_gradient_background_color_dark</color>
<color name="chooser_gradient_highlight">@color/loading_gradient_highlight_color_dark</color>
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index b1bcf72..3fd82b8 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -28,9 +28,4 @@
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Dialog" />
-
- <style name="TextAppearance.Material.Notification">
- <item name="textColor">@color/notification_secondary_text_color_dark</item>
- <item name="textSize">@dimen/notification_text_size</item>
- </style>
</resources>
\ No newline at end of file
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d76d32a..e2be98d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Herkent gezicht niet meer. Probeer het nog eens."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Lijkt te veel op elkaar. Verander je pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai je hoofd iets minder."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Draai je hoofd iets minder."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai je hoofd iets minder."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Zorg dat je gezicht volledig zichtbaar is."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinig de bovenkant van je scherm, inclusief de zwarte balk"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sneltoets gebruiken"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Kleurinversie"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurcorrectie"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Helderheid verlagen"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is ingeschakeld."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<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_dialog_turn_on_button" msgid="7921147002346108119">"Aanzetten"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorprivacy"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index f42d8ab..bc76142 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ଆଉ ମୁହଁ ଚିହ୍ନଟ କରିହେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ଅତ୍ୟନ୍ତ ସମପରି, ଦୟାକରି ଆପଣଙ୍କର ପୋଜ୍ ବଦଳାନ୍ତୁ।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ଆପଣଙ୍କର ମୁହଁ ଲୁଚାଉଥିବା ଜିନିଷକୁ କାଢ଼ି ଦିଅନ୍ତୁ।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"କଳା ବାର୍ ସମେତ ଆପଣଙ୍କ ସ୍କ୍ରିନ୍ର ଶୀର୍ଷକୁ ସଫା କରନ୍ତୁ"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ଶର୍ଟକଟ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ରଙ୍ଗ ବଦଳାଇବାର ସୁବିଧା"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ଉଜ୍ଜ୍ୱଳତା କମାନ୍ତୁ"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଚାଲୁ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବନ୍ଦ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SSଙ୍କ ଅନୁରୋଧକୁ ଭିଡିଓ କଲ୍ରେ ପରିବର୍ତ୍ତନ କରାଗଲା"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS ଅନୁରୋଧ, USSD ଅନୁରୋଧକୁ ପରିବର୍ତ୍ତନ ହେଲା"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ନୂତନ SS ଅନୁରୋଧରେ ପରିବର୍ତ୍ତନ ହେଲା"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ଫିସିଂ ଆଲର୍ଟ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ଆଲର୍ଟ କରାଯାଇଛି"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ବଢ଼ାନ୍ତୁ"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ଜାରି ରଖିବାକୁ, <b><xliff:g id="APP">%s</xliff:g></b> ଆପଣଙ୍କ ଡିଭାଇସର କ୍ୟାମେରାକୁ ଆକ୍ସେସ୍ ଆବଶ୍ୟକ କରେ।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ସେନ୍ସର୍ ଗୋପନୀୟତା"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 17a4944..c9f57ef 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ਹੁਣ ਚਿਹਰਾ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ਬਹੁਤ ਮਿਲਦਾ-ਜੁਲਦਾ ਹੈ, ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਅੰਦਾਜ਼ ਬਦਲੋ।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਲੁਕਾਉਣ ਵਾਲੀ ਕੋਈ ਵੀ ਚੀਜ਼ ਹਟਾਓ।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ਕਾਲੀ ਪੱਟੀ ਸਮੇਤ, ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਸਿਖਰ ਨੂੰ ਸਾਫ਼ ਕਰੋ"</string>
@@ -685,10 +686,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ਐਪ ਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਕੌਂਫਿਗਰੇਸ਼ਨ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਲਿਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਦੇਖਣਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ਧਾਰਕ ਨੂੰ ਕਿਸੇ ਹੋਰ ਐਪ ਲਈ ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਦਿੰਦਾ ਹੈ। ਸਧਾਰਨ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਵੇਗਾ।"</string>
- <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
- <skip />
- <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
- <skip />
+ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ਉੱਚ ਸੈਂਪਲਿੰਗ ਰੇਟ \'ਤੇ ਸੈਂਸਰ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ਐਪ ਨੂੰ 200 Hz ਤੋਂ ਵੱਧ ਦੀ ਦਰ \'ਤੇ ਸੈਂਸਰ ਡਾਟੇ ਦਾ ਨਮੂਨਾ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"ਪਾਸਵਰਡ ਨਿਯਮ ਸੈੱਟ ਕਰੋ"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"ਸਕ੍ਰੀਨ ਲਾਕ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਿੰਨ ਵਿੱਚ ਆਗਿਆ ਦਿੱਤੀ ਲੰਮਾਈ ਅਤੇ ਅੱਖਰਾਂ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ।"</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"ਸਕ੍ਰੀਨ ਅਣਲਾਕ ਕਰਨ ਦੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ \'ਤੇ ਨਿਗਰਾਨੀ ਰੱਖੋ"</string>
@@ -1669,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ਰੰਗ ਪਲਟਨਾ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ਰੰਗ ਸੁਧਾਈ"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ਚਮਕ ਘਟਾਓ"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
@@ -1873,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS ਬੇਨਤੀ ਨੂੰ ਵੀਡੀਓ ਕਾਲ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS ਬੇਨਤੀ ਨੂੰ USSD ਬੇਨਤੀ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ਨਵੀਂ SS ਬੇਨਤੀ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ਫ਼ਿਸ਼ਿੰਗ ਸੰਬੰਧੀ ਸੁਚੇਤਨਾ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ਸੁਚੇਤਨਾਵਾਂ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ਵਿਸਤਾਰ ਕਰੋ"</string>
@@ -2222,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ਜਾਰੀ ਰੱਖਣ ਲਈ, <b><xliff:g id="APP">%s</xliff:g></b> ਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰਾ ਤੱਕ ਪਹੁੰਚ ਦੀ ਲੋੜ ਹੈ।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ਚਾਲੂ ਕਰੋ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ਸੈਂਸਰ ਪਰਦੇਦਾਰੀ"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 14ca2b9..6c12366 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nie można już rozpoznać twarzy. Spróbuj ponownie."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Za mała różnica. Zmień pozycję."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Trochę mniej obróć głowę."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Trochę mniej obróć głowę."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Trochę mniej obróć głowę."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Usuń wszystko, co zasłania Ci twarz."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Wyczyść górną krawędź ekranu, w tym czarny pasek"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Użyj skrótu"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Odwrócenie kolorów"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcja kolorów"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zmniejsz jasność"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została włączona."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została wyłączona."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Żądanie SS zmienione na rozmowę wideo"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Żądanie SS zmienione na żądanie USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Zmieniono na nowe żądanie SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alert o phishingu"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil służbowy"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alert"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozwiń"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Włącz"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Poufność danych z czujników"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 3fbfd7e..d5cec26 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Incline a cabeça um pouco menos."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
@@ -867,7 +868,7 @@
<string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pausar"</string>
<string name="lockscreen_transport_play_description" msgid="106868788691652733">"Reproduzir"</string>
<string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"Parar"</string>
- <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Retroceder"</string>
+ <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Voltar"</string>
<string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"Avançar"</string>
<string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emergência"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Rede bloqueada"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir brilho"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index eb09af8..6867950 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Impossível reconhecer o rosto. Tente novamente."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecida, mude de pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Rode a cabeça um pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Rode a cabeça um pouco menos."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Rode a cabeça um pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo o que esteja a ocultar o seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior do ecrã, incluindo a barra preta."</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atalho"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correção da cor"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir o brilho"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas do volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Prima sem soltar as teclas de volume durante três segundos para utilizar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"O pedido SS foi alterado para uma videochamada."</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"O pedido SS foi alterado para um novo pedido USSD."</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Foi alterado para um novo pedido SS."</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing."</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade dos sensores"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bad102e..d5cec26 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Incline a cabeça um pouco menos."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
@@ -867,7 +868,7 @@
<string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pausar"</string>
<string name="lockscreen_transport_play_description" msgid="106868788691652733">"Reproduzir"</string>
<string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"Parar"</string>
- <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Retroceder"</string>
+ <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Voltar"</string>
<string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"Avançar"</string>
<string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emergência"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Rede bloqueada"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir brilho"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Solicitação SS alterada para videochamada"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Solicitação SS alterada para solicitação USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Alterada para uma nova solicitação SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 1e789e4..690884a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -609,7 +609,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nu se mai poate recunoaște fața. Încercați din nou."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Prea asemănător, schimbați poziția."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Întoarceți capul mai puțin."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Întoarceți capul mai puțin."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Întoarceți capul mai puțin."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Eliminați orice vă ascunde chipul."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Curățați partea de sus a ecranului, inclusiv bara neagră"</string>
@@ -1689,7 +1690,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizați comanda rapidă"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversarea culorilor"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corecția culorii"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduceți luminozitatea"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S-au apăsat lung tastele de volum. S-a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S-au apăsat lung tastele de volum. S-a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Apăsați ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pentru a continua, <b><xliff:g id="APP">%s</xliff:g></b> necesită acces la camera dispozitivului."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activați"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidențialitatea privind senzorii"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5cb8a50..84752d5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Не удалось распознать лицо. Повторите попытку."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Слишком похожее выражение лица. Измените позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Держите голову ровнее."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Держите голову ровнее."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Держите голову ровнее."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ваше лицо плохо видно."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Протрите верхнюю часть экрана (в том числе черную панель)."</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Использовать быстрое включение"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инверсия цветов"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Коррекция цвета"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Уменьшение яркости"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" отключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-запрос преобразован в видеовызов"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-запрос преобразован в USSD-запрос"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Преобразовано в SS-запрос"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Предупреждение о фишинге"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Рабочий профиль"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Отправлено оповещение"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Развернуть"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Чтобы продолжить, предоставьте приложению <b><xliff:g id="APP">%s</xliff:g></b> доступ к камере устройства."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Включить"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Конфиденциальность датчиков"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index bd311fb9..66547de 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"තවදුරටත් මුහුණ හඳුනාගත නොහැක. නැවත උත්සාහ කරන්න."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ඉතා සමානයි, ඔබේ හැඩ ගැසීම වෙනස් කරන්න."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ඔබේ මුහුණ සඟවන කිසිවක් ඉවත් කරන්න."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"කලු තීරුව ඇතුළුව, ඔබේ තිරයෙහි මුදුන පිරිසිදු කරන්න"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"කෙටිමඟ භාවිතා කරන්න"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"වර්ණ අපවර්තනය"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"වර්ණ නිවැරදි කිරීම"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"දීප්තිය අඩු කරන්න"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාත්මකයි."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාවිරහිතයි."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"දිගටම කර ගෙන යාමට, <b><xliff:g id="APP">%s</xliff:g></b> හට ඔබගේ උපාංගයෙහි කැමරාවට ප්රවේශය අවශ්යයි."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ක්රියාත්මක කරන්න"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"සංවේදක පෞද්ගලිකත්වය"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 825215b..487b818 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Tvár už nie je možné rozpoznať. Skúste to znova."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Príliš rovnaké, zmeňte postoj."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Otočte hlavu o niečo menej."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Otočte hlavu o niečo menej."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Otočte hlavu o niečo menej."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Odstráňte všetko, čo vám zakrýva tvár."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vyčistite hornú časť obrazovky vrátane čierneho panela"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použiť skratku"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzia farieb"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Úprava farieb"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zníženie jasu"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Žiadosť SS bola zmenená na videohovor"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Žiadosť SS bola zmenená na žiadosť USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Zmenené na novú žiadosť SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozornenie na phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Pracovný profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozornené"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozbaliť"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Zapnúť"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ochrana súkromia senzorov"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a27b805..87a66b3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Obraza ni več mogoče prepoznati. Poskusite znova."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Preveč podobno, spremenite položaj."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Glejte malce bolj naravnost."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malce manj nagnite glavo."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Glejte malce bolj naravnost."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Umaknite vse, kar vam morda zakriva obraz."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrhnji del zaslona, vključno s črno vrstico"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Uporabi bližnjico"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija barv"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Popravljanje barv"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zmanjšanje svetlosti"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vklopljena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je izklopljena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
@@ -2287,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Vklopi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Zasebnost pri uporabi tipal"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 823b963..4c37424 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Fytyra nuk mund të njihet më. Provo përsëri."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Tepër e ngjashme, ndrysho pozën"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Ktheje kokën pak më pak."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Ktheje kokën pak më pak."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Ktheje kokën pak më pak."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hiq gjithçka që fsheh fytyrën tënde."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pastro kreun e ekranit, duke përfshirë shiritin e zi"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Përdor shkurtoren"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Kthimi i ngjyrës"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korrigjimi i ngjyrës"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Redukto ndriçimin"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tastet e volumit të mbajtura shtypur. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> i aktivizuar."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tastet e volumit të mbajtura shtypur. U çaktivizua \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Kërkesa SS u ndryshua në telefonatë me video"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Kërkesa SS u ndryshua në kërkesë USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"U ndryshua në kërkesë të re SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Sinjalizim për mashtrim"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profili i punës"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Sinjalizuar"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Zgjero"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Aktivizo"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatësia e sensorit"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 74589a8..d061d6f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -609,7 +609,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Више не може да се препозна лице. Пробајте поново."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Превише је слично, промените позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Мало мање померите главу."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Мало мање померите главу."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Мало мање померите главу."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Уклоните све што вам заклања лице."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистите горњи део екрана, укључујући црну траку"</string>
@@ -1689,7 +1690,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Користи пречицу"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инверзија боја"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Корекција боја"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Смањите осветљеност"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је укључена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је искључена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> захтева приступ камери уређаја ради настављања."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Укључи"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Приватност сензора"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 47bfe0a..8288d41 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ansiktet kan inte längre kännas igen. Försök igen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"För likt. Ändra ansiktsposition."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vrid mindre på huvudet."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Vrid mindre på huvudet."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vrid mindre på huvudet."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ta bort allt som täcker ansiktet."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengör skärmens överkant, inklusive det svarta fältet"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Använd kortkommandot"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverterade färger"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Färgkorrigering"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Minska ljusstyrkan"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har aktiverats."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har inaktiverats."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-begäran har ändrats till videosamtal"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-begäran har ändrats till en USSD-begäran"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Har ändrats till ny SS-begäran"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varning om nätfiske"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Jobbprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Aviserad"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Utöka"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<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_dialog_turn_on_button" msgid="7921147002346108119">"Aktivera"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorintegritet"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index fcc9c9d..6ac7d2a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Haiwezi tena kutambua uso. Jaribu tena."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Inafanana sana, tafadhali badilisha mkao wako."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Geuza kichwa chako kidogo."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Geuza kichwa chako kidogo."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Geuza kichwa chako kidogo."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ondoa kitu chochote kinachoficha uso wako."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Safisha sehemu ya juu ya skrini yako, ikiwa ni pamoja na upau mweusi"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tumia Njia ya Mkato"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ugeuzaji rangi"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Usahihishaji wa rangi"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Punguza Ung\'aavu"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Vitufe vya sauti vilivyoshikiliwa. Umewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Vitufe vya sauti vimeshikiliwa. Umezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Washa"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Faragha ya Kitambuzi"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 535fb6c..1ac1734 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"முகத்தைக் கண்டறிய இயலவில்லை. மீண்டும் முயலவும்."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"மீண்டும் அதே போஸ் தருகிறீர்கள், வேறு முயலுங்கள்."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"தலையை லேசாகத் திருப்பவும்."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"தலையை லேசாகத் திருப்பவும்."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"உங்கள் தலையைச் சற்றுத் திருப்பவும்."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"உங்கள் முகத்தை மறைக்கும் அனைத்தையும் நீக்குக."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"திரையையும் அதிலுள்ள கருப்புப் பட்டியையும் சுத்தம் செய்யவும்"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ஷார்ட்கட்டைப் பயன்படுத்து"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"கலர் இன்வெர்ஷன்"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"வண்ணத் திருத்தம்"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ஒளிர்வைக் குறைத்தல்"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"தொடர, உங்கள் சாதனத்தின் கேமராவை அணுகுவதற்கு <b><xliff:g id="APP">%s</xliff:g></b> ஆப்ஸுக்கு அனுமதி வேண்டும்."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ஆன் செய்"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"சென்சார் தனியுரிமை"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 59d451a..9f822e3 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ఇక ముఖం గుర్తించలేదు. మళ్లీ ప్రయత్నించండి."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ఒకే మాదిరిగా ఉంది, దయచేసి భంగిమను మార్చండి."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"మీ తలను ఇంకాస్త తక్కువ తిప్పండి."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"మీ తలను ఇంకాస్త తక్కువ తిప్పండి."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"మీ తలను ఎడమ/కుడి వైపుగా ఇంకాస్త తిప్పండి."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"మీ ముఖానికి అడ్డుగా ఉన్నవాటిని తీసివేస్తుంది."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"నల్లని పట్టీతో సహా మీ స్క్రీన్ పైభాగం అంతటినీ శుభ్రంగా తుడవండి"</string>
@@ -685,10 +686,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"వీక్షణ అనుమతి వినియోగాన్ని ప్రారంభించండి"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"యాప్నకు అనుమతి వినియోగాన్ని ప్రారంభించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ యాప్లకు ఎప్పటికీ ఇటువంటి అనుమతి అవసరం ఉండదు."</string>
- <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
- <skip />
- <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
- <skip />
+ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"అధిక శాంపిల్ రేటు వద్ద సెన్సార్ డేటాను యాక్సెస్ చేయండి"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz కంటే ఎక్కువ రేట్ వద్ద శాంపిల్ సెన్సార్ డేటాకు యాప్ను అనుమతిస్తుంది"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"పాస్వర్డ్ నియమాలను సెట్ చేయండి"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"స్క్రీన్ లాక్ పాస్వర్డ్లు మరియు PINల్లో అనుమతించబడిన పొడవు మరియు అక్షరాలను నియంత్రిస్తుంది."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"స్క్రీన్ అన్లాక్ ప్రయత్నాలను పర్యవేక్షించండి"</string>
@@ -1669,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"సత్వరమార్గాన్ని ఉపయోగించు"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"కలర్ మార్పిడి"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"కలర్ సరిచేయడం"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ప్రకాశాన్ని తగ్గించండి"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string>
@@ -2221,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"కొనసాగించడానికి, <b><xliff:g id="APP">%s</xliff:g></b&gtకు మీ పరికరం యొక్క కెమెరా యాక్సెస్ అవసరం."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ఆన్ చేయి"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"సెన్సార్ గోప్యత"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index cb21c72..21865cd 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"จำใบหน้าไม่ได้แล้ว ลองอีกครั้ง"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ใกล้เคียงเกินไป โปรดเปลี่ยนท่าโพส"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"จัดตำแหน่งศีรษะให้ตรง"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"จัดตำแหน่งศีรษะให้ตรง"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"จัดตำแหน่งศีรษะให้ตรง"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"เอาสิ่งที่ปิดบังใบหน้าออก"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ทำความสะอาดด้านบนของหน้าจอ รวมถึงแถบสีดำ"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ใช้ทางลัด"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"การกลับสี"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"การแก้สี"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ลดความสว่าง"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว เปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว ปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> ต้องได้รับสิทธิ์เข้าถึงกล้องของอุปกรณ์เพื่อดำเนินการต่อ"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"เปิด"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ความเป็นส่วนตัวสำหรับเซ็นเซอร์"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6f00ba8..37d06f8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Hindi na makilala ang mukha. Subukang muli."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Masyadong magkatulad, pakibago ang pose mo."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Huwag masyadong lumingon."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Huwag masyadong tumingala o yumuko."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Huwag masyadong lumingon."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Alisin ang anumang humaharang sa iyong mukha."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Linisin ang itaas ng iyong screen, kasama ang itim na bar"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gamitin ang Shortcut"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Pag-invert ng Kulay"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Pagwawasto ng Kulay"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Bawasan ang Liwanag"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pinindot nang matagal ang volume keys. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Ginawang video call ang SS na kahilingan"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Ginawang USSD na kahilingan ang SS na kahilingan"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Ginawang bagong SS na kahilingan"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerto sa phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profile sa trabaho"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Naalertuhan"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Palawakin"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"I-on"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacy ng Sensor"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 67086d2..2132aac 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Yüz artık tanınamıyor. Tekrar deneyin."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Duruşunuz çok benzer, lütfen pozunuzu değiştirin."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı biraz daha az çevirin."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Başınızı biraz daha az çevirin."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı biraz daha az çevirin."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Yüzünüzün görünmesini engelleyen şeyleri kaldırın."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Siyah çubuk da dahil olmak üzere ekranınızın üst kısmını temizleyin"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kısayolu Kullan"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Rengi Ters Çevirme"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Renk Düzeltme"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Parlaklığı Azaltma"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kapatıldı."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS isteği görüntülü görüşme olarak değişti"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS isteği USSD isteği olarak değişti"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Yeni SS isteği olarak değişti"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Kimlik avı uyarısı"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"İş profili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Sesli uyarıldı"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Genişlet"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"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_dialog_turn_on_button" msgid="7921147002346108119">"Aç"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensör Gizliliği"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d6a3677..3b9db40 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -612,7 +612,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Розпізнати обличчя вже не вдається. Повторіть спробу."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Надто схоже на попередню спробу, змініть позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Трохи перемістіть обличчя."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Трохи перемістіть обличчя."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Трохи поверніть обличчя."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Приберіть об’єкти, які затуляють ваше обличчя."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистьте верхню частину екрана, зокрема чорну панель"</string>
@@ -1711,7 +1712,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Використовувати ярлик"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Інверсія кольорів"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Корекція кольорів"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Зменшення яскравості"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> увімкнено."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> вимкнено."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string>
@@ -1933,8 +1935,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Запит SS змінено на відеовиклик"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Запит SS змінено на запит USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Змінено на новий запит SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Попередження про фішинг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Робочий профіль"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Зі звуком"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Розгорнути"</string>
@@ -2288,4 +2289,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Щоб продовжити, надайте додатку <b><xliff:g id="APP">%s</xliff:g></b> доступ до камери пристрою."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Увімкнути"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Конфіденційність датчиків"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 9a7cb87..c10f3e9 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"اب چہرے کی شناخت نہیں کر سکتے۔ پھر آزمائيں۔"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"کافی ملتا جلتا ہے، براہ کرم اپنا پوز بدلیں۔"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"اپنا سر تھوڑا کم کریں۔"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"اپنا سر تھوڑا کم کریں۔"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"اپنا سر تھوڑا کم کریں۔"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"آپ کے چہرہ کو چھپانے والی ہر چیز کو ہٹائیں۔"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"سیاہ بار سمیت، اپنی اسکرین کے اوپری حصے کو صاف کریں"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"شارٹ کٹ استعمال کریں"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"رنگوں کی تقلیب"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"رنگ کی تصحیح"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"چمک کم کریں"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آن ہے۔"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آف ہے۔"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"جاری رکھنے کیلئے <b><xliff:g id="APP">%s</xliff:g></b> کو آپ کے آلے کے کیمرے تک رسائی درکار ہے۔"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"آن کریں"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"سینسر کی رازداری"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 60134a47..f77de7d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -606,7 +606,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Yuz tanilmadi. Qaytadan urining."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Yuz ifodasi oldingiday. Holatingizni oʻzgartiring."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Boshingizni asta buring."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Boshingizni asta buring."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Boshingizni asta qiyalang."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Boshingizni asta buring."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Yuzingizni berkitayotgan narsalarni olib tashlang."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Ekranning yuqori qismini, shuningdek, qora panelni ham tozalang"</string>
@@ -1667,7 +1667,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tezkor ishga tushirishdan foydalanish"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ranglarni akslantirish"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Rangni tuzatish"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Yorqinlikni pasaytirish"</string>
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Yorqinlikni pasaytirish"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> yoqildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> faolsizlantirildi."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatidan foydalanish uchun ikkala ovoz balandligi tugmalarini uzoq bosib turing"</string>
@@ -1871,8 +1871,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS talabi video chaqiruvga almashtirildi"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS talabi USSD talabiga almashtirildi"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Yangi SS talabiga almashtirildi"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Fishing signali"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ish profili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ogohlantirildi"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Yoyish"</string>
@@ -2220,4 +2219,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Davom etish uchun <b><xliff:g id="APP">%s</xliff:g></b> qurilmangiz kamerasiga kirishi kerak."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Yoqish"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorlar maxfiyligi"</string>
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ilova belgisi"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Ilova brendining rasmi"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 25f0644..baf0b86d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Không nhận ra khuôn mặt. Hãy thử lại."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Khuôn mặt quá giống nhau, vui lòng đổi tư thế."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Hãy bớt di chuyển đầu."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Hãy bớt di chuyển đầu."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Hãy bớt di chuyển đầu."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hãy loại bỏ mọi thứ che khuất khuôn mặt bạn."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vệ sinh phần đầu màn hình, bao gồm cả thanh màu đen"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sử dụng phím tắt"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Đảo màu"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Chỉnh màu"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Giảm độ sáng"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã bật."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã tắt."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Yêu cầu SS đã thay đổi thành cuộc gọi video"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Yêu cầu SS đã thay đổi thành yêu cầu USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Đã thay đổi thành yêu cầu SS mới"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Cảnh báo về hành vi lừa đảo"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Hồ sơ công việc"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Đã phát âm báo"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Mở rộng"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Để 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_dialog_turn_on_button" msgid="7921147002346108119">"Bật"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Quyền riêng tư khi sử dụng cảm biến"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 358367e..9345fc82 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"已无法识别人脸,请重试。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"与先前的姿势太相近,请换一个姿势。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"请将您的头稍微上下倾斜。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"请将您的头稍微上下倾斜。"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"请将您的头稍微左右旋转。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"请移除所有遮挡您面部的物体。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"请将屏幕顶部(包括黑色条栏)清理干净"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用快捷方式"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"颜色反转"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"调低亮度"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已开启。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已关闭。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要继续操作,请向<b><xliff:g id="APP">%s</xliff:g></b>授予设备的相机使用权。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"开启"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"传感器隐私权"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e4fa2e0..1187f00 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"無法再識別臉孔。請再試一次。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"臉孔位置太相近,請改變您的姿勢。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"減少頭部左右轉動幅度。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"減少頭部上下轉動幅度。"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"減少頭部左右轉動幅度。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"移除遮住您臉孔的任何東西。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂部,包括黑色列"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用快速鍵"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"色彩反轉"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"調低亮度"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要繼續,<b><xliff:g id="APP">%s</xliff:g></b> 需要裝置的相機存取權。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"開啟"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"感應器私隱"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 49e57b3..9492572 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"已無法辨識臉孔,請再試一次。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"與先前的姿勢太相似,請換一個姿勢。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"請將你的頭部稍微向左或向右轉動。"</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"請將你的頭部稍微向上或向下傾斜。"</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"請將你的頭部稍微向左或向右旋轉。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"請移除任何會遮住臉孔的物體。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂端,包括黑色橫列"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用捷徑"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"色彩反轉"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"調低亮度"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
@@ -2219,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要繼續操作,請將裝置的相機存取權授予「<xliff:g id="APP">%s</xliff:g>」<b></b>。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"開啟"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"感應器隱私權"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9a21e78..e5a026bd 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -606,7 +606,8 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ayisakwazi ukubona ubuso. Zama futhi."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Kufana kakhulu, sicela ushintshe ukuma kwakho."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Jikisa ikhanda lakho kancane."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Jikisa ikhanda lakho kancane."</string>
+ <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+ <skip />
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Jikisa ikhanda lakho kancane."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Susa noma yini efihle ubuso bakho."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hlanza okuphezulu kwesikrini sakho, kufaka phakathi ibha emnyama"</string>
@@ -1667,7 +1668,8 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sebenzisa isinqamuleli"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ukuguqulwa kombala"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Ukulungiswa kombala"</string>
- <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Nciphisa ukukhanya"</string>
+ <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+ <skip />
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivuliwe."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivaliwe."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Isicelo se-SS sishintshele kukholi yevidiyo"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Isicelo se-SS sishintshele kusicelo se-USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Ishintshele kusicelo esisha se-SS"</string>
- <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
- <skip />
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Isexwayiso sobugebengu bokweba imininingwane ebucayi"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Iphrofayela yomsebenzi"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Kuxwayisiwe"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Nweba"</string>
@@ -2220,4 +2221,8 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Ukuze uqhubeke, <b>i-<xliff:g id="APP">%s</xliff:g></b> idinga ukufinyelela ikhamera yakho."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Vula"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ubumfihlo Benzwa"</string>
+ <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+ <skip />
+ <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 735e1224..100983b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3564,16 +3564,6 @@
<attr name="__removed2" format="boolean" />
<!-- Specifies whether the IME supports showing inline suggestions. -->
<attr name="supportsInlineSuggestions" format="boolean" />
- <!-- Specify one or more configuration changes that the IME will handle itself. If not
- specified, the IME will be restarted if any of these configuration changes happen in
- the system. Otherwise, the IME will remain running and its
- {@link android.inputmethodservice.InputMethodService#onConfigurationChanged}
- method is called with the new configuration.
- <p>Note that all of these configuration changes can impact the
- resource values seen by the application, so you will generally need
- to re-retrieve all resources (including view layouts, drawables, etc)
- to correctly handle any configuration change.-->
- <attr name="configChanges" />
</declare-styleable>
<!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 59c260c..d79c01f 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -143,6 +143,10 @@
<color name="notification_default_color_dark">@color/primary_text_default_material_light</color>
<color name="notification_default_color_light">#a3202124</color>
+ <color name="notification_primary_text_color_current">@color/notification_primary_text_color_light</color>
+ <color name="notification_secondary_text_color_current">@color/notification_secondary_text_color_light</color>
+ <color name="notification_default_color_current">@color/notification_default_color_light</color>
+
<color name="notification_default_color">#757575</color> <!-- Gray 600 -->
<color name="notification_action_button_text_color">@color/notification_default_color</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 592a3a1..12cb398 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1953,6 +1953,8 @@
<string name="config_systemShell" translatable="false">com.android.shell</string>
<!-- The name of the package that will hold the system contacts role. -->
<string name="config_systemContacts" translatable="false">com.android.contacts</string>
+ <!-- The name of the package that will hold the speech recognizer role by default. -->
+ <string name="config_systemSpeechRecognizer" translatable="false"></string>
<!-- The name of the package that will be allowed to change its components' label/icon. -->
<string name="config_overrideComponentUiPackage" translatable="false"></string>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 695a831..c2b6b99 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -319,26 +319,22 @@
<!-- The top padding for the notification expand button. -->
<dimen name="notification_expand_button_padding_top">1dp</dimen>
- <!-- minimum vertical margin for the headerless notification content, when cap = 60dp -->
- <dimen name="notification_headerless_margin_minimum">8dp</dimen>
+ <!-- Vertical margin for the headerless notification content, when content has 1 line -->
+ <!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
+ <dimen name="notification_headerless_margin_oneline">16dp</dimen>
- <!-- extra vertical margin for the headerless notification content, when cap = 60dp -->
- <dimen name="notification_headerless_margin_extra">10dp</dimen>
-
- <!-- minimum vertical margin for the headerless notification content, when cap = 48dp -->
- <dimen name="notification_headerless_margin_constrained_minimum">14dp</dimen>
-
- <!-- extra vertical margin for the headerless notification content, when cap = 48dp -->
- <dimen name="notification_headerless_margin_constrained_extra">4dp</dimen>
+ <!-- Vertical margin for the headerless notification content, when content has 2 lines -->
+ <!-- 20 * 2 (margins) + 24 * 2 (2 lines) = 88 (notification) -->
+ <dimen name="notification_headerless_margin_twoline">20dp</dimen>
<!-- The height of each of the 1 or 2 lines in the headerless notification template -->
- <dimen name="notification_headerless_line_height">20sp</dimen>
+ <dimen name="notification_headerless_line_height">24dp</dimen>
<!-- vertical margin for the headerless notification content -->
<dimen name="notification_headerless_min_height">56dp</dimen>
<!-- Height of a small notification in the status bar -->
- <dimen name="notification_min_height">76dp</dimen>
+ <dimen name="notification_min_height">88dp</dimen>
<!-- The width of the big icons in notifications. -->
<dimen name="notification_large_icon_width">64dp</dimen>
@@ -738,10 +734,11 @@
<!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
<dimen name="notification_media_image_max_width">280dp</dimen>
<!-- The size of the right icon -->
- <dimen name="notification_right_icon_size">52dp</dimen>
+ <dimen name="notification_right_icon_size">48dp</dimen>
<!-- The top and bottom margin of the right icon in the normal notification states -->
- <dimen name="notification_right_icon_headerless_margin">12dp</dimen>
+ <dimen name="notification_right_icon_headerless_margin">20dp</dimen>
<!-- The top margin of the right icon in the "big" notification states -->
+ <!-- TODO(b/181048615): Move the large icon below the expander in big states -->
<dimen name="notification_right_icon_big_margin_top">16dp</dimen>
<!-- The size of the left icon -->
<dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9b2573f..2004d0a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3166,6 +3166,8 @@
<public name="config_customMediaKeyDispatcher" />
<!-- @hide @SystemApi -->
<public name="config_customMediaSessionPolicyProvider" />
+ <!-- @hide @SystemApi -->
+ <public name="config_systemSpeechRecognizer" />
</public-group>
<public-group type="id" first-id="0x01020055">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3505dee..71ba44b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1644,7 +1644,7 @@
<!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
<string name="face_acquired_pan_too_extreme">Turn your head a little less.</string>
<!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
- <string name="face_acquired_tilt_too_extreme">Turn your head a little less.</string>
+ <string name="face_acquired_tilt_too_extreme">Tilt your head a little less.</string>
<!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
<string name="face_acquired_roll_too_extreme">Turn your head a little less.</string>
<!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
@@ -4538,7 +4538,7 @@
<string name="color_correction_feature_name">Color Correction</string>
<!-- Title of Reduce Brightness feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
- <string name="reduce_bright_colors_feature_name">Reduce Brightness</string>
+ <string name="reduce_bright_colors_feature_name">Reduce brightness</string>
<!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_enabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned on.</string>
@@ -5011,6 +5011,9 @@
<!-- Content description of the alerting icon in the notification. [CHAR_LIMIT=NONE] -->
<string name="notification_alerted_content_description">Alerted</string>
+ <!-- Default content description of the verification icon in the call notification. [CHAR_LIMIT=NONE] -->
+ <string name="notification_verified_content_description">Verified</string>
+
<!-- Content description of the expand button icon in the notification when collaped.-->
<string name="expand_button_content_description_collapsed">Expand</string>
@@ -5849,4 +5852,8 @@
<!--- Label for notification channel for all sensor privacy related notifications. [CHAR LIMIT=NONE] -->
<string name="sensor_privacy_notification_channel_label">Sensor Privacy</string>
+ <!-- Content description for the icon on the splash screen. [CHAR LIMIT=50] -->
+ <string name="splash_screen_view_icon_description">Application icon</string>
+ <!-- Content description for the branding image on the splash screen. [CHAR LIMIT=50] -->
+ <string name="splash_screen_view_branding_description">Application branding image</string>
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 158289a..3c4a5d4 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -466,18 +466,20 @@
</style>
<style name="TextAppearance.Material.Notification">
- <item name="textColor">@color/notification_secondary_text_color_light</item>
+ <item name="textColor">@color/notification_secondary_text_color_current</item>
<item name="textSize">@dimen/notification_text_size</item>
</style>
<style name="TextAppearance.Material.Notification.Reply" />
<style name="TextAppearance.Material.Notification.Title">
+ <item name="textColor">@color/notification_primary_text_color_current</item>
<item name="fontFamily">sans-serif-medium</item>
<item name="textSize">@dimen/notification_title_text_size</item>
</style>
<style name="TextAppearance.Material.Notification.BigTitle">
+ <item name="textColor">@color/notification_primary_text_color_current</item>
<item name="fontFamily">sans-serif-medium</item>
<item name="textSize">@dimen/notification_big_title_text_size</item>
</style>
@@ -492,9 +494,8 @@
<style name="TextAppearance.Material.Notification.Time" parent="TextAppearance.Material.Notification.Info" />
- <style name="TextAppearance.Material.Notification.Emphasis">
- <item name="textColor">#66000000</item>
- </style>
+ <!-- unused; keep identical to parent -->
+ <style name="TextAppearance.Material.Notification.Emphasis"/>
<style name="TextAppearance.Material.Notification.Conversation.AppName" parent="TextAppearance.Material.Notification.Title">
<item name="android:textSize">16sp</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7ad05de..dbb584d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2895,8 +2895,6 @@
<java-symbol type="id" name="alternate_expand_target" />
<java-symbol type="id" name="notification_header" />
<java-symbol type="id" name="notification_top_line" />
- <java-symbol type="id" name="notification_headerless_margin_extra_top" />
- <java-symbol type="id" name="notification_headerless_margin_extra_bottom" />
<java-symbol type="id" name="time_divider" />
<java-symbol type="id" name="header_text_divider" />
<java-symbol type="id" name="header_text_secondary_divider" />
@@ -2918,8 +2916,8 @@
<java-symbol type="dimen" name="notification_header_icon_size" />
<java-symbol type="dimen" name="notification_header_app_name_margin_start" />
<java-symbol type="dimen" name="notification_header_separating_margin" />
- <java-symbol type="dimen" name="notification_headerless_margin_constrained_minimum" />
- <java-symbol type="dimen" name="notification_headerless_margin_constrained_extra" />
+ <java-symbol type="dimen" name="notification_headerless_margin_oneline" />
+ <java-symbol type="dimen" name="notification_headerless_margin_twoline" />
<java-symbol type="string" name="default_notification_channel_label" />
<java-symbol type="string" name="importance_from_user" />
<java-symbol type="string" name="importance_from_person" />
@@ -3112,8 +3110,10 @@
<java-symbol type="dimen" name="call_notification_collapsible_indent"/>
<java-symbol type="drawable" name="ic_call_answer" />
<java-symbol type="drawable" name="ic_call_decline" />
+ <java-symbol type="id" name="verification_divider" />
<java-symbol type="id" name="verification_icon" />
<java-symbol type="id" name="verification_text" />
+ <java-symbol type="string" name="notification_verified_content_description" />
<!-- Notification handler / dashboard package -->
<java-symbol type="string" name="config_notificationHandlerPackage" />
diff --git a/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java b/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java
new file mode 100644
index 0000000..1cf4302
--- /dev/null
+++ b/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java
@@ -0,0 +1,133 @@
+/*
+ * 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.os;
+
+import android.annotation.SuppressLint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.MergedConfiguration;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+
+/**
+ * Benchmark of read/write large Parcelable class. This also shows the performance of different
+ * implementations for nested Parcelable class:
+ * <ul>
+ * <li>Well-written read/writeFromParcel (direct access)</li>
+ * <li>read/writeTypedObject (object creation + addition int to indicate nullity)</li>
+ * <li>read/writeParcelable (object creation + addition type String)</li>
+ * </ul>
+ */
+public class ParcelableBenchmark {
+ private Parcel mParcel;
+
+ @BeforeExperiment
+ protected void setUp() {
+ mParcel = Parcel.obtain();
+ }
+
+ @AfterExperiment
+ protected void tearDown() {
+ mParcel.recycle();
+ mParcel = null;
+ }
+
+ public void timeReadWriteMergedConfiguration(int reps) {
+ final MergedConfiguration mergedConfiguration = new MergedConfiguration();
+ for (int i = 0; i < reps; i++) {
+ mergedConfiguration.writeToParcel(mParcel, 0);
+ mParcel.setDataPosition(0);
+ mergedConfiguration.readFromParcel(mParcel);
+ }
+ }
+
+ public void timeReadWriteInsetsState(int reps) {
+ final InsetsState insetsState = new InsetsState();
+ for (int i = 0; i < InsetsState.SIZE; i++) {
+ insetsState.addSource(new InsetsSource(i));
+ }
+ for (int i = 0; i < reps; i++) {
+ insetsState.writeToParcel(mParcel, 0);
+ mParcel.setDataPosition(0);
+ insetsState.readFromParcel(mParcel);
+ }
+ }
+
+ public void timeReadWritePointArray(int reps) {
+ final PointArray pointArray = new PointArray();
+ for (int i = 0; i < reps; i++) {
+ pointArray.writeToParcel(mParcel, 0);
+ mParcel.setDataPosition(0);
+ pointArray.readFromParcel(mParcel);
+ }
+ }
+
+ public void timeReadWritePointArrayFast(int reps) {
+ final PointArrayFast pointArray = new PointArrayFast();
+ for (int i = 0; i < reps; i++) {
+ pointArray.writeToParcel(mParcel, 0);
+ mParcel.setDataPosition(0);
+ pointArray.readFromParcel(mParcel);
+ }
+ }
+
+ @SuppressLint("ParcelCreator")
+ private static class PointArray implements Parcelable {
+ Rect mBounds = new Rect();
+ Point[] mPoints = new Point[10];
+ {
+ for (int i = 0; i < mPoints.length; i++) {
+ mPoints[i] = new Point();
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mBounds, flags);
+ dest.writeParcelableArray(mPoints, flags);
+ }
+
+ void readFromParcel(Parcel in) {
+ mBounds = in.readParcelable(Rect.class.getClassLoader());
+ mPoints = in.readParcelableArray(Point.class.getClassLoader(), Point.class);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+ }
+
+ @SuppressLint("ParcelCreator")
+ private static class PointArrayFast extends PointArray {
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mBounds.writeToParcel(dest, flags);
+ dest.writeTypedArray(mPoints, flags);
+ }
+
+ @Override
+ void readFromParcel(Parcel in) {
+ mBounds.readFromParcel(in);
+ in.readTypedArray(mPoints, Point.CREATOR);
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/app/backup/BackupAgentTest.java b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
index ea903f2..37cf470 100644
--- a/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
@@ -57,14 +57,6 @@
}
@Test
- public void testGetIncludeExcludeRules_isMigration_returnsEmptyRules() throws Exception {
- mBackupAgent = getAgentForOperationType(OperationType.MIGRATION);
-
- IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme);
- assertThat(rules).isEqualTo(IncludeExcludeRules.emptyRules());
- }
-
- @Test
public void testGetIncludeExcludeRules_isNotMigration_returnsRules() throws Exception {
PathWithRequiredFlags path = new PathWithRequiredFlags("path", /* requiredFlags */ 0);
Map<String, Set<PathWithRequiredFlags>> includePaths = Collections.singletonMap("test",
diff --git a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
index 1573c19..7cb6804 100644
--- a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
+++ b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
@@ -37,6 +37,7 @@
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Parcel;
+import android.os.UserHandle;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -124,13 +125,13 @@
}
@Test
- public void testUid() {
+ public void testUserHandle() {
PeopleSpaceTile tile = new PeopleSpaceTile
.Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
- .setUid(42)
+ .setUserHandle(new UserHandle(0))
.build();
- assertThat(tile.getUid()).isEqualTo(42);
+ assertThat(tile.getUserHandle()).isEqualTo(new UserHandle(0));
}
@Test
@@ -227,7 +228,7 @@
.setUserName("name")
.setUserIcon(mIcon)
.setContactUri(Uri.parse("contact"))
- .setUid(42)
+ .setUserHandle(new UserHandle(1))
.setPackageName("package.name")
.setLastInteractionTimestamp(7L)
.setIsImportantConversation(true)
@@ -246,7 +247,7 @@
assertThat(readTile.getUserName()).isEqualTo(tile.getUserName());
assertThat(readTile.getUserIcon().toString()).isEqualTo(tile.getUserIcon().toString());
assertThat(readTile.getContactUri()).isEqualTo(tile.getContactUri());
- assertThat(readTile.getUid()).isEqualTo(tile.getUid());
+ assertThat(readTile.getUserHandle()).isEqualTo(tile.getUserHandle());
assertThat(readTile.getPackageName()).isEqualTo(tile.getPackageName());
assertThat(readTile.getLastInteractionTimestamp()).isEqualTo(
tile.getLastInteractionTimestamp());
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 50b52eb..6c8b941 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -148,13 +148,15 @@
PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("k", 4);
IBinder assistToken = new Binder();
+ IBinder shareableActivityToken = new Binder();
Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder()
.setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
.setOverrideConfig(overrideConfig).setCompatInfo(compat).setReferrer(referrer)
.setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
.setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
- .setIsForward(true).setAssistToken(assistToken).build();
+ .setIsForward(true).setAssistToken(assistToken)
+ .setShareableActivityToken(shareableActivityToken).build();
LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build();
LaunchActivityItem item = itemSupplier.get();
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 02e75dd..1a06789e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -109,6 +109,7 @@
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
private IBinder mAssistToken;
+ private IBinder mShareableActivityToken;
private FixedRotationAdjustments mFixedRotationAdjustments;
LaunchActivityItemBuilder setIntent(Intent intent) {
@@ -196,6 +197,11 @@
return this;
}
+ LaunchActivityItemBuilder setShareableActivityToken(IBinder shareableActivityToken) {
+ mShareableActivityToken = shareableActivityToken;
+ return this;
+ }
+
LaunchActivityItemBuilder setFixedRotationAdjustments(FixedRotationAdjustments fra) {
mFixedRotationAdjustments = fra;
return this;
@@ -206,7 +212,8 @@
mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
- null /* activityClientController */, mFixedRotationAdjustments);
+ null /* activityClientController */, mFixedRotationAdjustments,
+ mShareableActivityToken);
}
}
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index f6d985b..6f3d7ae 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -207,6 +207,7 @@
.setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic())
.setPendingNewIntents(referrerIntentList()).setIsForward(true)
.setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments)
+ .setShareableActivityToken(new Binder())
.build();
writeAndPrepareForReading(item);
diff --git a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
index da92e69..ffe93bc 100644
--- a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
@@ -47,15 +47,16 @@
final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW);
final ShortcutInfo shortcut = new AppSearchShortcutInfo.Builder(id)
.setActivity(activity)
- .setText(id)
+ .setLongLabel(id)
.setIconResName(shortcutIconResName)
.setIntent(shortcutIntent)
.setPerson(person)
.setCategories(categorySet)
.setFlags(ShortcutInfo.FLAG_LONG_LIVED)
.build()
- .toShortcutInfo();
+ .toShortcutInfo(0);
+ assertThat(shortcut.getUserId()).isEqualTo(0);
assertThat(shortcut.getId()).isEqualTo(id);
assertThat(shortcut.getShortLabel()).isEqualTo(id);
assertThat(shortcut.getIconResName()).isEqualTo(shortcutIconResName);
diff --git a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
deleted file mode 100644
index 8906149..0000000
--- a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.inputmethodservice;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.rule.ServiceTestRule;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeoutException;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class InputMethodServiceTest {
- private InputMethodService mService;
- private Context mContext;
- @Rule
- public final ServiceTestRule serviceRule = new ServiceTestRule();
-
- @Before
- public void setUp() throws TimeoutException {
- mContext = getInstrumentation().getContext();
- mService = new InputMethodService();
- }
-
- @Test
- public void testShouldImeRestartForConfig() throws Exception {
- // Make sure we preserve Pre-S behavior i.e. Service restarts.
- mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
- Configuration config = mContext.getResources().getConfiguration();
- mService.setLastKnownConfig(config);
- assertTrue("IME should restart for Pre-S",
- mService.shouldImeRestartForConfig(config));
-
- // IME shouldn't restart on targetSdk S+ (with no config changes).
- mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S;
- assertFalse("IME shouldn't restart for S+",
- mService.shouldImeRestartForConfig(config));
-
- // Screen density changed but IME doesn't handle congfigChanges
- config.densityDpi = 99;
- assertTrue("IME should restart for unhandled configChanges",
- mService.shouldImeRestartForConfig(config));
-
- // opt-in IME to handle config changes.
- mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY);
- assertFalse("IME shouldn't restart for S+ since it handles configChanges",
- mService.shouldImeRestartForConfig(config));
- }
-}
diff --git a/core/tests/coretests/src/android/view/BlurAggregatorTest.java b/core/tests/coretests/src/android/view/BlurAggregatorTest.java
new file mode 100644
index 0000000..b01f275
--- /dev/null
+++ b/core/tests/coretests/src/android/view/BlurAggregatorTest.java
@@ -0,0 +1,318 @@
+/*
+ * 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.view;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable.Aggregator;
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable.BlurRegion;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BlurAggregatorTest {
+ private static final int TEST_BLUR_RADIUS = 30;
+ private static final int TEST_FRAME_NUMBER = 1;
+
+ private Context mContext;
+
+ private Aggregator mAggregator;
+ private BackgroundBlurDrawable mDrawable;
+
+ private ViewRootImpl mViewRoot;
+
+ @Before
+ public void setUp() {
+ mContext = getInstrumentation().getTargetContext();
+ getInstrumentation().runOnMainSync(() -> {
+ mViewRoot = new ViewRootImpl(mContext, mContext.getDisplayNoVerify());
+ });
+ mAggregator = new Aggregator(mViewRoot);
+ mDrawable = createTestBackgroundBlurDrawable();
+ }
+
+ private BackgroundBlurDrawable createTestBackgroundBlurDrawable() {
+ final BackgroundBlurDrawable drawable = mAggregator.createBackgroundBlurDrawable(mContext);
+ drawable.setBlurRadius(TEST_BLUR_RADIUS);
+ final boolean hasUpdates = mAggregator.hasUpdates();
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ mAggregator.getBlurRegionsToDispatchToSf(TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+ return drawable;
+ }
+
+ @Test
+ public void testBlurRadiusUpdatePropagatesToRenderThreadIfNeeded() {
+ mDrawable.setBlurRadius(TEST_BLUR_RADIUS);
+ assertFalse(mAggregator.hasUpdates());
+
+ mDrawable.setBlurRadius(0);
+ assertTrue(mAggregator.hasUpdates());
+ BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(0, blurRegions.length);
+ assertFalse(mAggregator.hasUpdates());
+
+ mDrawable.setBlurRadius(TEST_BLUR_RADIUS);
+ assertTrue(mAggregator.hasUpdates());
+ blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+ assertEquals(TEST_BLUR_RADIUS, blurRegions[0].blurRadius);
+ assertFalse(mAggregator.hasUpdates());
+
+ }
+
+ @Test
+ public void testAlphaUpdatePropagatesToRenderThreadIfNeeded() {
+ mDrawable.setAlpha(20);
+ assertTrue(mAggregator.hasUpdates());
+ BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+ assertEquals(20 / 255f, blurRegions[0].alpha);
+ assertFalse(mAggregator.hasUpdates());
+
+ mDrawable.setAlpha(20);
+ assertFalse(mAggregator.hasUpdates());
+
+ mDrawable.setAlpha(0);
+ assertTrue(mAggregator.hasUpdates());
+ blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(0, blurRegions.length);
+ assertFalse(mAggregator.hasUpdates());
+ }
+
+ @Test
+ public void testCornerRadiusUpdatePropagatesToRenderThreadIfNeeded() {
+ mDrawable.setCornerRadius(1f, 2f, 3f, 4f);
+ assertTrue(mAggregator.hasUpdates());
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+ assertEquals(1f, blurRegions[0].cornerRadiusTL);
+ assertEquals(2f, blurRegions[0].cornerRadiusTR);
+ assertEquals(3f, blurRegions[0].cornerRadiusBL);
+ assertEquals(4f, blurRegions[0].cornerRadiusBR);
+ assertFalse(mAggregator.hasUpdates());
+ }
+
+ @Test
+ public void testVisibleUpdatePropagatesToRenderThreadIfNeeded() {
+ mDrawable.setVisible(false, /* restart= */false);
+ assertTrue(mAggregator.hasUpdates());
+ BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(0, blurRegions.length);
+ assertFalse(mAggregator.hasUpdates());
+
+ mDrawable.setVisible(true, /* restart= */ false);
+ assertTrue(mAggregator.hasUpdates());
+ blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+ assertEquals(TEST_BLUR_RADIUS, blurRegions[0].blurRadius);
+ assertFalse(mAggregator.hasUpdates());
+ }
+
+ @Test
+ public void testBlurRegionCopyForRtIsSameIfNoUiUpdates() {
+ mDrawable.setBlurRadius(30);
+ BlurRegion[] blurRegions1 = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions1.length);
+ assertEquals(30, blurRegions1[0].blurRadius);
+
+ BlurRegion[] blurRegions2 = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(blurRegions1, blurRegions2);
+ }
+
+ @Test
+ public void testPositionUpdateAppearsInBlurRegion() {
+ BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+
+ mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+ mAggregator.getBlurRegionsToDispatchToSf(TEST_FRAME_NUMBER, blurRegions,
+ mAggregator.hasUpdates());
+ assertEquals(1, blurRegions[0].rect.left);
+ assertEquals(2, blurRegions[0].rect.top);
+ assertEquals(3, blurRegions[0].rect.right);
+ assertEquals(4, blurRegions[0].rect.bottom);
+ }
+
+ @Test
+ public void testNoBlurRegionsDispatchedWhenNoUpdates() {
+ final boolean hasUpdates = mAggregator.hasUpdates();
+ assertFalse(hasUpdates);
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+
+ float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+ assertNull(blurRegionsForSf);
+ }
+
+ @Test
+ public void testBlurRegionDispatchedIfOnlyDrawableUpdated() {
+ mDrawable.setBlurRadius(50);
+ final boolean hasUpdates = mAggregator.hasUpdates();
+ assertTrue(hasUpdates);
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+
+ float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+ assertNotNull(blurRegionsForSf);
+ assertEquals(1, blurRegionsForSf.length);
+ assertEquals(50f, blurRegionsForSf[0][0]);
+ }
+
+ @Test
+ public void testBlurRegionDispatchedIfOnlyPositionUpdated() {
+ final boolean hasUpdates = mAggregator.hasUpdates();
+ assertFalse(hasUpdates);
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+
+ mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+ float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+ assertNotNull(blurRegionsForSf);
+ assertEquals(1, blurRegionsForSf.length);
+ assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSf[0][0]);
+ assertEquals(1f, blurRegionsForSf[0][2]);
+ assertEquals(2f, blurRegionsForSf[0][3]);
+ assertEquals(3f, blurRegionsForSf[0][4]);
+ assertEquals(4f, blurRegionsForSf[0][5]);
+ }
+
+ @Test
+ public void testPositionUpdateIsAppliedInNextFrameIfMissed() {
+ final boolean hasUpdates = mAggregator.hasUpdates();
+ assertFalse(hasUpdates);
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+
+ mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+ float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER + 1, blurRegions, hasUpdates);
+ assertNotNull(blurRegionsForSf);
+ assertEquals(1, blurRegionsForSf.length);
+ assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSf[0][0]);
+ assertEquals(1f, blurRegionsForSf[0][2]);
+ assertEquals(2f, blurRegionsForSf[0][3]);
+ assertEquals(3f, blurRegionsForSf[0][4]);
+ assertEquals(4f, blurRegionsForSf[0][5]);
+ }
+
+ @Test
+ public void testMultipleDrawablesDispatchedToSfIfOneIsUpdated() {
+ final BackgroundBlurDrawable drawable2 = createTestBackgroundBlurDrawable();
+ drawable2.setBlurRadius(50);
+ final boolean hasUpdates = mAggregator.hasUpdates();
+ assertTrue(hasUpdates);
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(2, blurRegions.length);
+
+ // Check that an update in one of the drawables triggers a dispatch of all blur regions
+ float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+ assertNotNull(blurRegionsForSf);
+ assertEquals(2, blurRegionsForSf.length);
+
+ // Check that the Aggregator deleted all position updates for frame TEST_FRAME_NUMBER
+ blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER, blurRegions, /* hasUiUpdates= */ false);
+ assertNull(blurRegionsForSf);
+
+ // Check that a position update triggers a dispatch of all blur regions
+ drawable2.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+ blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER + 1, blurRegions, hasUpdates);
+ assertNotNull(blurRegionsForSf);
+ assertEquals(2, blurRegionsForSf.length);
+ }
+
+ @Test
+ public void testUiThreadUpdatesDoNotChangeStateOnRenderThread() {
+ // Updates for frame N
+ mDrawable.setBlurRadius(50);
+ mDrawable.setCornerRadius(1, 2, 3, 4);
+ mDrawable.setAlpha(20);
+
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+ assertEquals(1, blurRegions.length);
+ assertEquals(50, blurRegions[0].blurRadius);
+ assertEquals(20 / 255f, blurRegions[0].alpha);
+ assertEquals(1f, blurRegions[0].cornerRadiusTL);
+ assertEquals(2f, blurRegions[0].cornerRadiusTR);
+ assertEquals(3f, blurRegions[0].cornerRadiusBL);
+ assertEquals(4f, blurRegions[0].cornerRadiusBR);
+
+ // Updates for frame N+1
+ mDrawable.setBlurRadius(60);
+ mDrawable.setCornerRadius(10, 20, 30, 40);
+ mDrawable.setAlpha(40);
+
+ // Assert state for frame N is untouched
+ assertEquals(50, blurRegions[0].blurRadius);
+ assertEquals(20 / 255f, blurRegions[0].alpha);
+ assertEquals(1f, blurRegions[0].cornerRadiusTL);
+ assertEquals(2f, blurRegions[0].cornerRadiusTR);
+ assertEquals(3f, blurRegions[0].cornerRadiusBL);
+ assertEquals(4f, blurRegions[0].cornerRadiusBR);
+ }
+
+ @Test
+ public void testPositionUpdatesForFutureFramesAreNotAppliedForCurrentFrame() {
+ final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+
+ mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+ mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER + 1, 5, 6, 7, 8);
+
+ final float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER, blurRegions, /* hasUiUpdates= */ false);
+ assertNotNull(blurRegionsForSf);
+ assertEquals(1, blurRegionsForSf.length);
+ // Assert state for first frame is not affected by update for second frame
+ assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSf[0][0]);
+ assertEquals(1f, blurRegionsForSf[0][2]);
+ assertEquals(2f, blurRegionsForSf[0][3]);
+ assertEquals(3f, blurRegionsForSf[0][4]);
+ assertEquals(4f, blurRegionsForSf[0][5]);
+
+ final float[][] blurRegionsForSfForNextFrame = mAggregator.getBlurRegionsToDispatchToSf(
+ TEST_FRAME_NUMBER + 1, blurRegions, /* hasUiUpdates= */ false);
+ assertNotNull(blurRegionsForSfForNextFrame);
+ assertEquals(1, blurRegionsForSfForNextFrame.length);
+ // Assert second frame updates are applied normally
+ assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSfForNextFrame[0][0]);
+ assertEquals(5f, blurRegionsForSfForNextFrame[0][2]);
+ assertEquals(6f, blurRegionsForSfForNextFrame[0][3]);
+ assertEquals(7f, blurRegionsForSfForNextFrame[0][4]);
+ assertEquals(8f, blurRegionsForSfForNextFrame[0][5]);
+ }
+
+}
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
index b9cf1e4..516fb76 100644
--- a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
+++ b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
@@ -16,16 +16,12 @@
package android.view;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.InstrumentationRegistry.getTargetContext;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -35,6 +31,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.ICancellationSignal;
import androidx.test.runner.AndroidJUnit4;
@@ -42,9 +39,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
/**
* Tests of {@link ScrollCaptureConnection}.
@@ -56,261 +51,138 @@
private final Point mPositionInWindow = new Point(1, 2);
private final Rect mLocalVisibleRect = new Rect(2, 3, 4, 5);
private final Rect mScrollBounds = new Rect(3, 4, 5, 6);
+ private final TestScrollCaptureCallback mCallback = new TestScrollCaptureCallback();
+
+ private ScrollCaptureTarget mTarget;
+ private ScrollCaptureConnection mConnection;
private Handler mHandler;
- private ScrollCaptureTarget mTarget1;
@Mock
private Surface mSurface;
@Mock
- private IScrollCaptureCallbacks mConnectionCallbacks;
+ private IScrollCaptureCallbacks mRemote;
@Mock
- private View mMockView1;
- @Mock
- private ScrollCaptureCallback mCallback1;
+ private View mView;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mHandler = new Handler(getTargetContext().getMainLooper());
+ when(mSurface.isValid()).thenReturn(true);
+ when(mView.getScrollCaptureHint()).thenReturn(View.SCROLL_CAPTURE_HINT_INCLUDE);
- when(mMockView1.getHandler()).thenReturn(mHandler);
- when(mMockView1.getScrollCaptureHint()).thenReturn(View.SCROLL_CAPTURE_HINT_INCLUDE);
-
- mTarget1 = new ScrollCaptureTarget(
- mMockView1, mLocalVisibleRect, mPositionInWindow, mCallback1);
- mTarget1.setScrollBounds(mScrollBounds);
- }
-
- /** Test the DelayedAction timeout helper class works as expected. */
- @Test
- public void testDelayedAction() {
- Runnable action = Mockito.mock(Runnable.class);
- ScrollCaptureConnection.DelayedAction delayed =
- new ScrollCaptureConnection.DelayedAction(mHandler, 100, action);
- try {
- Thread.sleep(200);
- } catch (InterruptedException ex) {
- /* ignore */
- }
- getInstrumentation().waitForIdleSync();
- assertFalse(delayed.cancel());
- assertFalse(delayed.timeoutNow());
- verify(action, times(1)).run();
- }
-
- /** Test the DelayedAction cancel() */
- @Test
- public void testDelayedAction_cancel() {
- Runnable action = Mockito.mock(Runnable.class);
- ScrollCaptureConnection.DelayedAction delayed =
- new ScrollCaptureConnection.DelayedAction(mHandler, 100, action);
- try {
- Thread.sleep(50);
- } catch (InterruptedException ex) {
- /* ignore */
- }
- assertTrue(delayed.cancel());
- assertFalse(delayed.timeoutNow());
- try {
- Thread.sleep(200);
- } catch (InterruptedException ex) {
- /* ignore */
- }
- getInstrumentation().waitForIdleSync();
- verify(action, never()).run();
- }
-
- /** Test the DelayedAction timeoutNow() - for testing only */
- @Test
- public void testDelayedAction_timeoutNow() {
- Runnable action = Mockito.mock(Runnable.class);
- ScrollCaptureConnection.DelayedAction delayed =
- new ScrollCaptureConnection.DelayedAction(mHandler, 100, action);
- try {
- Thread.sleep(50);
- } catch (InterruptedException ex) {
- /* ignore */
- }
- assertTrue(delayed.timeoutNow());
- assertFalse(delayed.cancel());
- getInstrumentation().waitForIdleSync();
- verify(action, times(1)).run();
+ mTarget = new ScrollCaptureTarget(mView, mLocalVisibleRect, mPositionInWindow, mCallback);
+ mTarget.setScrollBounds(mScrollBounds);
+ mConnection = new ScrollCaptureConnection(Runnable::run, mTarget, mRemote);
}
/** Test creating a client with valid info */
@Test
public void testConstruction() {
- new ScrollCaptureConnection(mTarget1, mConnectionCallbacks);
+ ScrollCaptureTarget target = new ScrollCaptureTarget(
+ mView, mLocalVisibleRect, mPositionInWindow, mCallback);
+ target.setScrollBounds(new Rect(1, 2, 3, 4));
+ new ScrollCaptureConnection(Runnable::run, target, mRemote);
}
/** Test creating a client fails if arguments are not valid. */
@Test
public void testConstruction_requiresScrollBounds() {
try {
- mTarget1.setScrollBounds(null);
- new ScrollCaptureConnection(mTarget1, mConnectionCallbacks);
+ mTarget.setScrollBounds(null);
+ new ScrollCaptureConnection(Runnable::run, mTarget, mRemote);
fail("An exception was expected.");
} catch (RuntimeException ex) {
// Ignore, expected.
}
}
- @SuppressWarnings("SameParameterValue")
- private static Answer<Void> runRunnable(int arg) {
- return invocation -> {
- Runnable r = invocation.getArgument(arg);
- r.run();
- return null;
- };
- }
-
- @SuppressWarnings("SameParameterValue")
- private static Answer<Void> reportBufferSent(int sessionArg, long frameNum, Rect capturedArea) {
- return invocation -> {
- ScrollCaptureSession session = invocation.getArgument(sessionArg);
- session.notifyBufferSent(frameNum, capturedArea);
- return null;
- };
- }
-
/** @see ScrollCaptureConnection#startCapture(Surface) */
@Test
public void testStartCapture() throws Exception {
- final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
- mConnectionCallbacks);
+ mConnection.startCapture(mSurface);
- // Have the session start accepted immediately
- doAnswer(runRunnable(1)).when(mCallback1)
- .onScrollCaptureStart(any(ScrollCaptureSession.class), any(Runnable.class));
- connection.startCapture(mSurface);
- getInstrumentation().waitForIdleSync();
+ mCallback.completeStartRequest();
+ assertTrue(mConnection.isStarted());
- verify(mCallback1, times(1))
- .onScrollCaptureStart(any(ScrollCaptureSession.class), any(Runnable.class));
- verify(mConnectionCallbacks, times(1)).onCaptureStarted();
- verifyNoMoreInteractions(mConnectionCallbacks);
+ verify(mRemote, times(1)).onCaptureStarted();
+ verifyNoMoreInteractions(mRemote);
}
@Test
- public void testStartCaptureTimeout() throws Exception {
- final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
- mConnectionCallbacks);
- connection.startCapture(mSurface);
+ public void testStartCapture_cancellation() throws Exception {
+ ICancellationSignal signal = mConnection.startCapture(mSurface);
+ signal.cancel();
- // Force timeout to fire
- connection.getTimeoutAction().timeoutNow();
+ mCallback.completeStartRequest();
+ assertFalse(mConnection.isStarted());
- getInstrumentation().waitForIdleSync();
- verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
- }
-
- private void startCapture(ScrollCaptureConnection connection) throws Exception {
- doAnswer(runRunnable(1)).when(mCallback1)
- .onScrollCaptureStart(any(ScrollCaptureSession.class), any(Runnable.class));
- connection.startCapture(mSurface);
- getInstrumentation().waitForIdleSync();
- reset(mCallback1, mConnectionCallbacks);
+ verifyNoMoreInteractions(mRemote);
}
/** @see ScrollCaptureConnection#requestImage(Rect) */
@Test
public void testRequestImage() throws Exception {
- final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
- mConnectionCallbacks);
- startCapture(connection);
+ mConnection.startCapture(mSurface);
+ mCallback.completeStartRequest();
+ reset(mRemote);
- // Stub the callback to complete the request immediately
- doAnswer(reportBufferSent(/* sessionArg */ 0, /* frameNum */ 1L, new Rect(1, 2, 3, 4)))
- .when(mCallback1)
- .onScrollCaptureImageRequest(any(ScrollCaptureSession.class), any(Rect.class));
+ mConnection.requestImage(new Rect(1, 2, 3, 4));
+ mCallback.completeImageRequest(new Rect(1, 2, 3, 4));
- // Make the inbound binder call
- connection.requestImage(new Rect(1, 2, 3, 4));
-
- // Wait for handler thread dispatch
- getInstrumentation().waitForIdleSync();
- verify(mCallback1, times(1)).onScrollCaptureImageRequest(
- any(ScrollCaptureSession.class), eq(new Rect(1, 2, 3, 4)));
-
- // Wait for binder thread dispatch
- getInstrumentation().waitForIdleSync();
- verify(mConnectionCallbacks, times(1))
- .onCaptureBufferSent(eq(1L), eq(new Rect(1, 2, 3, 4)));
-
- verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+ verify(mRemote, times(1))
+ .onImageRequestCompleted(eq(0), eq(new Rect(1, 2, 3, 4)));
+ verifyNoMoreInteractions(mRemote);
}
@Test
- public void testRequestImageTimeout() throws Exception {
- final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
- mConnectionCallbacks);
- startCapture(connection);
+ public void testRequestImage_cancellation() throws Exception {
+ mConnection.startCapture(mSurface);
+ mCallback.completeStartRequest();
+ reset(mRemote);
- // Make the inbound binder call
- connection.requestImage(new Rect(1, 2, 3, 4));
+ ICancellationSignal signal = mConnection.requestImage(new Rect(1, 2, 3, 4));
+ signal.cancel();
+ mCallback.completeImageRequest(new Rect(1, 2, 3, 4));
- // Wait for handler thread dispatch
- getInstrumentation().waitForIdleSync();
- verify(mCallback1, times(1)).onScrollCaptureImageRequest(
- any(ScrollCaptureSession.class), eq(new Rect(1, 2, 3, 4)));
-
- // Force timeout to fire
- connection.getTimeoutAction().timeoutNow();
- getInstrumentation().waitForIdleSync();
-
- // (callback not stubbed, does nothing)
- // Timeout triggers request to end capture
- verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
- verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+ verifyNoMoreInteractions(mRemote);
}
/** @see ScrollCaptureConnection#endCapture() */
@Test
public void testEndCapture() throws Exception {
- final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
- mConnectionCallbacks);
- startCapture(connection);
+ mConnection.startCapture(mSurface);
+ mCallback.completeStartRequest();
+ reset(mRemote);
- // Stub the callback to complete the request immediately
- doAnswer(runRunnable(0))
- .when(mCallback1)
- .onScrollCaptureEnd(any(Runnable.class));
+ mConnection.endCapture();
+ mCallback.completeEndRequest();
- // Make the inbound binder call
- connection.endCapture();
+ // And the reply is sent
+ verify(mRemote, times(1)).onCaptureEnded();
+ verifyNoMoreInteractions(mRemote);
+ }
- // Wait for handler thread dispatch
- getInstrumentation().waitForIdleSync();
- verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
+ /** @see ScrollCaptureConnection#endCapture() */
+ @Test
+ public void testEndCapture_cancellation() throws Exception {
+ mConnection.startCapture(mSurface);
+ mCallback.completeStartRequest();
+ reset(mRemote);
- // Wait for binder thread dispatch
- getInstrumentation().waitForIdleSync();
- verify(mConnectionCallbacks, times(1)).onConnectionClosed();
+ ICancellationSignal signal = mConnection.endCapture();
+ signal.cancel();
+ mCallback.completeEndRequest();
- verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+ verifyNoMoreInteractions(mRemote);
}
@Test
- public void testEndCaptureTimeout() throws Exception {
- final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
- mConnectionCallbacks);
- startCapture(connection);
-
- // Make the inbound binder call
- connection.endCapture();
-
- // Wait for handler thread dispatch
- getInstrumentation().waitForIdleSync();
- verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
-
- // Force timeout to fire
- connection.getTimeoutAction().timeoutNow();
-
- // Wait for binder thread dispatch
- getInstrumentation().waitForIdleSync();
- verify(mConnectionCallbacks, times(1)).onConnectionClosed();
-
- verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+ public void testClose() throws Exception {
+ mConnection.close();
+ assertFalse(mConnection.isConnected());
+ verifyNoMoreInteractions(mRemote);
}
+
}
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java b/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java
new file mode 100644
index 0000000..cc229e1
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java
@@ -0,0 +1,415 @@
+/*
+ * 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.view;
+
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.CancellationSignal;
+import android.os.SystemClock;
+
+import androidx.annotation.NonNull;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Tests of {@link ScrollCaptureTargetSelector}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ScrollCaptureSearchResultsTest {
+
+
+ private static final Rect EMPTY_RECT = new Rect();
+ private static final String TAG = "Test";
+
+ private final Executor mDirectExec = Runnable::run;
+ private Executor mBgExec;
+
+ @Before
+ public void setUp() {
+ mBgExec = Executors.newSingleThreadExecutor();
+ }
+
+ @Test
+ public void testNoTargets() {
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+ assertTrue(results.isComplete());
+
+ assertNull("Expected null due to empty queue", results.getTopResult());
+ }
+
+ @Test
+ public void testNoValidTargets() {
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+
+ FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mDirectExec);
+ callback1.setScrollBounds(EMPTY_RECT);
+ ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
+ new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+ // Supplies scrollBounds = empty rect
+ FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mDirectExec);
+ callback2.setScrollBounds(EMPTY_RECT);
+ ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
+ new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
+
+ results.addTarget(target1);
+ results.addTarget(target2);
+
+ assertTrue(results.isComplete());
+ assertNull("Expected null due to no valid targets", results.getTopResult());
+ }
+
+ @Test
+ public void testSingleTarget() {
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+ FakeScrollCaptureCallback callback = new FakeScrollCaptureCallback(mDirectExec);
+ ScrollCaptureTarget target = createTarget(callback,
+ new Rect(20, 30, 40, 50), new Point(10, 10),
+ View.SCROLL_CAPTURE_HINT_AUTO);
+ callback.setScrollBounds(new Rect(2, 2, 18, 18));
+
+ results.addTarget(target);
+ assertTrue(results.isComplete());
+
+ ScrollCaptureTarget result = results.getTopResult();
+ assertSame("Excepted the same target as a result", target, result);
+ assertEquals("result has wrong scroll bounds",
+ new Rect(2, 2, 18, 18), result.getScrollBounds());
+ }
+
+ @Test
+ public void testSingleTarget_backgroundThread() throws InterruptedException {
+ FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mBgExec);
+ ScrollCaptureTarget target1 = createTarget(callback1,
+ new Rect(20, 30, 40, 50), new Point(10, 10),
+ View.SCROLL_CAPTURE_HINT_AUTO);
+ callback1.setDelay(100);
+ callback1.setScrollBounds(new Rect(2, 2, 18, 18));
+
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+ results.addTarget(target1);
+
+ CountDownLatch latch = new CountDownLatch(1);
+ results.setOnCompleteListener(latch::countDown);
+ if (!latch.await(200, TimeUnit.MILLISECONDS)) {
+ fail("onComplete listener was expected");
+ }
+
+ ScrollCaptureTarget result = results.getTopResult();
+ assertSame("Excepted the single target1 as a result", target1, result);
+ assertEquals("Result has wrong scroll bounds",
+ new Rect(2, 2, 18, 18), result.getScrollBounds());
+ }
+
+ @Test
+ public void testRanking() {
+
+ // 1 - Empty
+ FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mDirectExec);
+ callback1.setScrollBounds(EMPTY_RECT);
+ ViewGroup targetView1 = new FakeView(getTargetContext(), 0, 0, 60, 60, 1);
+ ScrollCaptureTarget target1 = createTargetWithView(targetView1, callback1,
+ new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+ // 2 - 10x10 + HINT_INCLUDE
+ FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mDirectExec);
+ callback2.setScrollBounds(new Rect(0, 0, 10, 10));
+ ViewGroup targetView2 = new FakeView(getTargetContext(), 0, 0, 60, 60, 2);
+ ScrollCaptureTarget target2 = createTargetWithView(targetView2, callback2,
+ new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_INCLUDE);
+
+ // 3 - 20x20 + AUTO
+ FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback(mDirectExec);
+ callback3.setScrollBounds(new Rect(0, 0, 20, 20));
+ ViewGroup targetView3 = new FakeView(getTargetContext(), 0, 0, 60, 60, 3);
+ ScrollCaptureTarget target3 = createTargetWithView(targetView3, callback3,
+ new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+ // 4 - 30x30 + AUTO
+ FakeScrollCaptureCallback callback4 = new FakeScrollCaptureCallback(mDirectExec);
+ callback4.setScrollBounds(new Rect(0, 0, 10, 10));
+ ViewGroup targetView4 = new FakeView(getTargetContext(), 0, 0, 60, 60, 4);
+ ScrollCaptureTarget target4 = createTargetWithView(targetView4, callback4,
+ new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+ // 5 - 10x10 + child of #4
+ FakeScrollCaptureCallback callback5 = new FakeScrollCaptureCallback(mDirectExec);
+ callback5.setScrollBounds(new Rect(0, 0, 10, 10));
+ ViewGroup targetView5 = new FakeView(getTargetContext(), 0, 0, 60, 60, 5);
+ ScrollCaptureTarget target5 = createTargetWithView(targetView5, callback5,
+ new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+ targetView4.addView(targetView5);
+
+ // 6 - 20x20 + child of #4
+ FakeScrollCaptureCallback callback6 = new FakeScrollCaptureCallback(mDirectExec);
+ callback6.setScrollBounds(new Rect(0, 0, 20, 20));
+ ViewGroup targetView6 = new FakeView(getTargetContext(), 0, 0, 60, 60, 6);
+ ScrollCaptureTarget target6 = createTargetWithView(targetView6, callback6,
+ new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+ targetView4.addView(targetView6);
+
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+ results.addTarget(target1);
+ results.addTarget(target2);
+ results.addTarget(target3);
+ results.addTarget(target4);
+ results.addTarget(target5);
+ results.addTarget(target6);
+ assertTrue(results.isComplete());
+
+ // Verify "top" result
+ assertEquals(target2, results.getTopResult());
+
+ // Verify priority ("best" first)
+ assertThat(results.getTargets())
+ .containsExactly(
+ target2,
+ target6,
+ target5,
+ target4,
+ target3,
+ target1);
+ }
+
+ /**
+ * If a timeout expires, late results are ignored.
+ */
+ @Test
+ public void testTimeout() {
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+
+ // callback 1, 10x10, hint=AUTO, responds after 100ms from bg thread
+ FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mBgExec);
+ callback1.setScrollBounds(new Rect(5, 5, 15, 15));
+ callback1.setDelay(100);
+ ScrollCaptureTarget target1 = createTarget(
+ callback1, new Rect(20, 30, 40, 50), new Point(10, 10),
+ View.SCROLL_CAPTURE_HINT_AUTO);
+ results.addTarget(target1);
+
+ // callback 2, 20x20, hint=AUTO, responds after 5s from bg thread
+ FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mBgExec);
+ callback2.setScrollBounds(new Rect(0, 0, 20, 20));
+ callback2.setDelay(1000);
+ ScrollCaptureTarget target2 = createTarget(
+ callback2, new Rect(20, 30, 40, 50), new Point(10, 10),
+ View.SCROLL_CAPTURE_HINT_AUTO);
+ results.addTarget(target2);
+
+ // callback 3, 20x20, hint=INCLUDE, responds after 10s from bg thread
+ FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback(mBgExec);
+ callback3.setScrollBounds(new Rect(0, 0, 20, 20));
+ callback3.setDelay(1500);
+ ScrollCaptureTarget target3 = createTarget(
+ callback3, new Rect(20, 30, 40, 50), new Point(10, 10),
+ View.SCROLL_CAPTURE_HINT_INCLUDE);
+ results.addTarget(target3);
+
+ // callback 1 will be received
+ // callback 2 & 3 will be ignored due to timeout
+ SystemClock.sleep(500);
+ results.finish();
+
+ ScrollCaptureTarget result = results.getTopResult();
+ assertSame("Expected target1 as the result, due to timeouts of others", target1, result);
+ assertEquals("callback1 should have been called",
+ 1, callback1.getOnScrollCaptureSearchCount());
+ assertEquals("callback2 should have been called",
+ 1, callback2.getOnScrollCaptureSearchCount());
+ assertEquals("callback3 should have been called",
+ 1, callback3.getOnScrollCaptureSearchCount());
+
+ assertEquals("result has wrong scroll bounds",
+ new Rect(5, 5, 15, 15), result.getScrollBounds());
+ assertNull("target2 should not have been updated",
+ target2.getScrollBounds());
+ assertNull("target3 should not have been updated",
+ target3.getScrollBounds());
+ }
+
+ @Test
+ public void testWithCallbackMultipleReplies() {
+ // Calls response methods 3 times each
+ ScrollCaptureCallback callback1 = new CallbackStub() {
+ @Override
+ public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+ @NonNull Consumer<Rect> onReady) {
+ onReady.accept(new Rect(1, 2, 3, 4));
+ onReady.accept(new Rect(9, 10, 11, 12));
+ }
+ };
+
+ ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
+ new Point(10, 10), View.SCROLL_CAPTURE_HINT_AUTO);
+
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+ results.addTarget(target1);
+ assertTrue(results.isComplete());
+
+ ScrollCaptureTarget result = results.getTopResult();
+ assertSame("Expected target1", target1, result);
+ assertEquals("result has wrong scroll bounds",
+ new Rect(1, 2, 3, 4), result.getScrollBounds());
+ }
+
+ private void setupTargetView(View view, Rect localVisibleRect, int scrollCaptureHint) {
+ view.setScrollCaptureHint(scrollCaptureHint);
+ view.onVisibilityAggregated(true);
+ // Treat any offset as padding, outset localVisibleRect on all sides and use this as
+ // child bounds
+ Rect bounds = new Rect(localVisibleRect);
+ bounds.inset(-bounds.left, -bounds.top, bounds.left, bounds.top);
+ view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ view.onVisibilityAggregated(true);
+ }
+
+ private ScrollCaptureTarget createTarget(ScrollCaptureCallback callback, Rect localVisibleRect,
+ Point positionInWindow, int scrollCaptureHint) {
+ View mockView = new View(getTargetContext());
+ return createTargetWithView(mockView, callback, localVisibleRect, positionInWindow,
+ scrollCaptureHint);
+ }
+
+ private ScrollCaptureTarget createTargetWithView(View view, ScrollCaptureCallback callback,
+ Rect localVisibleRect, Point positionInWindow, int scrollCaptureHint) {
+ setupTargetView(view, localVisibleRect, scrollCaptureHint);
+ return new ScrollCaptureTarget(view, localVisibleRect, positionInWindow, callback);
+ }
+
+
+ static class FakeView extends ViewGroup implements ViewParent {
+ FakeView(Context context, int l, int t, int r, int b, int id) {
+ super(context);
+ layout(l, t, r, b);
+ setId(id);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ }
+ }
+
+ static class FakeScrollCaptureCallback implements ScrollCaptureCallback {
+ private final Executor mExecutor;
+ private Rect mScrollBounds;
+ private long mDelayMillis;
+ private int mOnScrollCaptureSearchCount;
+ FakeScrollCaptureCallback(Executor executor) {
+ mExecutor = executor;
+ }
+ public int getOnScrollCaptureSearchCount() {
+ return mOnScrollCaptureSearchCount;
+ }
+
+ @Override
+ public void onScrollCaptureSearch(CancellationSignal signal, Consumer<Rect> onReady) {
+ mOnScrollCaptureSearchCount++;
+ run(() -> {
+ Rect b = getScrollBounds();
+ onReady.accept(b);
+ });
+ }
+
+ @Override
+ public void onScrollCaptureStart(ScrollCaptureSession session, CancellationSignal signal,
+ Runnable onReady) {
+ run(onReady);
+ }
+
+ @Override
+ public void onScrollCaptureImageRequest(ScrollCaptureSession session,
+ CancellationSignal signal, Rect captureArea, Consumer<Rect> onReady) {
+ run(() -> onReady.accept(captureArea));
+ }
+
+ @Override
+ public void onScrollCaptureEnd(Runnable onReady) {
+ run(onReady);
+ }
+
+ public void setScrollBounds(@Nullable Rect scrollBounds) {
+ mScrollBounds = scrollBounds;
+ }
+
+ public void setDelay(long delayMillis) {
+ mDelayMillis = delayMillis;
+ }
+
+ protected Rect getScrollBounds() {
+ return mScrollBounds;
+ }
+
+ protected void run(Runnable r) {
+ mExecutor.execute(() -> {
+ delay();
+ r.run();
+ });
+ }
+
+ protected void delay() {
+ if (mDelayMillis > 0) {
+ try {
+ Thread.sleep(mDelayMillis);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+ static class CallbackStub implements ScrollCaptureCallback {
+ @Override
+ public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+ @NonNull Consumer<Rect> onReady) {
+ }
+
+ @Override
+ public void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Runnable onReady) {
+ }
+
+ @Override
+ public void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+ Consumer<Rect> onReady) {
+ }
+
+ @Override
+ public void onScrollCaptureEnd(@NonNull Runnable onReady) {
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureTargetResolverTest.java b/core/tests/coretests/src/android/view/ScrollCaptureTargetResolverTest.java
deleted file mode 100644
index 8b21b8e..0000000
--- a/core/tests/coretests/src/android/view/ScrollCaptureTargetResolverTest.java
+++ /dev/null
@@ -1,498 +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.
- */
-
-package android.view;
-
-import static androidx.test.InstrumentationRegistry.getTargetContext;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Handler;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.LinkedList;
-import java.util.function.Consumer;
-
-/**
- * Tests of {@link ScrollCaptureTargetResolver}.
- */
-@RunWith(AndroidJUnit4.class)
-public class ScrollCaptureTargetResolverTest {
-
- private static final long TEST_TIMEOUT_MS = 2000;
- private static final long RESOLVER_TIMEOUT_MS = 1000;
-
- private Handler mHandler;
- private TargetConsumer mTargetConsumer;
-
- @Before
- public void setUp() {
- mTargetConsumer = new TargetConsumer();
- mHandler = new Handler(getTargetContext().getMainLooper());
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testEmptyQueue() throws InterruptedException {
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(new LinkedList<>());
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- // Test only
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertNull("Expected null due to empty queue", result);
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testNoValidTargets() throws InterruptedException {
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
- // Supplies scrollBounds = null
- FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
- callback1.setScrollBounds(null);
- ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
- new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
- // Supplies scrollBounds = empty rect
- FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
- callback2.setScrollBounds(new Rect());
- ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
- new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
-
- targetQueue.add(target1);
- targetQueue.add(target2);
-
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- // Test only
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertNull("Expected null due to no valid targets", result);
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testSingleTarget() throws InterruptedException {
- FakeScrollCaptureCallback callback = new FakeScrollCaptureCallback();
- ScrollCaptureTarget target = createTarget(callback,
- new Rect(20, 30, 40, 50), new Point(10, 10),
- View.SCROLL_CAPTURE_HINT_AUTO);
- callback.setScrollBounds(new Rect(2, 2, 18, 18));
-
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
- targetQueue.add(target);
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- // Test only
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertSame("Excepted the same target as a result", target, result);
- assertEquals("result has wrong scroll bounds",
- new Rect(2, 2, 18, 18), result.getScrollBounds());
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testSingleTarget_backgroundThread() throws InterruptedException {
- BackgroundTestCallback callback1 = new BackgroundTestCallback();
- ScrollCaptureTarget target1 = createTarget(callback1,
- new Rect(20, 30, 40, 50), new Point(10, 10),
- View.SCROLL_CAPTURE_HINT_AUTO);
- callback1.setDelay(100);
- callback1.setScrollBounds(new Rect(2, 2, 18, 18));
-
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
- targetQueue.add(target1);
-
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- // Test only
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertSame("Excepted the single target1 as a result", target1, result);
- assertEquals("Result has wrong scroll bounds",
- new Rect(2, 2, 18, 18), result.getScrollBounds());
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testPreferNonEmptyBounds() throws InterruptedException {
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
- FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
- callback1.setScrollBounds(new Rect());
- ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
- new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
- FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
- callback2.setScrollBounds(new Rect(0, 0, 20, 20));
- ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
- new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
-
- FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback();
- callback3.setScrollBounds(null);
- ScrollCaptureTarget target3 = createTarget(callback3, new Rect(20, 30, 40, 50),
- new Point(0, 40), View.SCROLL_CAPTURE_HINT_AUTO);
-
- targetQueue.add(target1);
- targetQueue.add(target2); // scrollBounds not null or empty()
- targetQueue.add(target3);
-
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertEquals("Expected " + target2 + " as a result", target2, result);
- assertEquals("result has wrong scroll bounds",
- new Rect(0, 0, 20, 20), result.getScrollBounds());
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testPreferHintInclude() throws InterruptedException {
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
- FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
- callback1.setScrollBounds(new Rect(0, 0, 20, 20));
- ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
- new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
- FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
- callback2.setScrollBounds(new Rect(1, 1, 19, 19));
- ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
- new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
-
- FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback();
- callback3.setScrollBounds(new Rect(2, 2, 18, 18));
- ScrollCaptureTarget target3 = createTarget(callback3, new Rect(20, 30, 40, 50),
- new Point(0, 40), View.SCROLL_CAPTURE_HINT_AUTO);
-
- targetQueue.add(target1);
- targetQueue.add(target2); // * INCLUDE > AUTO
- targetQueue.add(target3);
-
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertEquals("input = " + targetQueue + " Expected " + target2
- + " as the result, due to hint=INCLUDE", target2, result);
- assertEquals("result has wrong scroll bounds",
- new Rect(1, 1, 19, 19), result.getScrollBounds());
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testDescendantPreferred() throws InterruptedException {
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
- ViewGroup targetView1 = new FakeRootView(getTargetContext(), 0, 0, 60, 60); // 60x60
- ViewGroup targetView2 = new FakeRootView(getTargetContext(), 20, 30, 40, 50); // 20x20
- ViewGroup targetView3 = new FakeRootView(getTargetContext(), 5, 5, 15, 15); // 10x10
-
- targetView1.addView(targetView2);
- targetView2.addView(targetView3);
-
- // Create first target with an unrelated parent
- FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
- callback1.setScrollBounds(new Rect(0, 0, 60, 60));
- ScrollCaptureTarget target1 = createTargetWithView(targetView1, callback1,
- new Rect(0, 0, 60, 60),
- new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
- // Create second target associated with a view within parent2
- FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
- callback2.setScrollBounds(new Rect(0, 0, 20, 20));
- ScrollCaptureTarget target2 = createTargetWithView(targetView2, callback2,
- new Rect(0, 0, 20, 20),
- new Point(20, 30), View.SCROLL_CAPTURE_HINT_AUTO);
-
- // Create third target associated with a view within parent3
- FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback();
- callback3.setScrollBounds(new Rect(0, 0, 15, 15));
- ScrollCaptureTarget target3 = createTargetWithView(targetView3, callback3,
- new Rect(0, 0, 15, 15),
- new Point(25, 35), View.SCROLL_CAPTURE_HINT_AUTO);
-
- targetQueue.add(target1); // auto, 60x60
- targetQueue.add(target2); // auto, 20x20
- targetQueue.add(target3); // auto, 15x15 <- innermost scrollable
-
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- // Test only
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertSame("Expected target3 as the result, due to relation", target3, result);
- assertEquals("result has wrong scroll bounds",
- new Rect(0, 0, 15, 15), result.getScrollBounds());
- }
-
- /**
- * If a timeout expires, late results are ignored.
- */
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testTimeout() throws InterruptedException {
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
- // callback 1, 10x10, hint=AUTO, responds immediately from bg thread
- BackgroundTestCallback callback1 = new BackgroundTestCallback();
- callback1.setScrollBounds(new Rect(5, 5, 15, 15));
- ScrollCaptureTarget target1 = createTarget(
- callback1, new Rect(20, 30, 40, 50), new Point(10, 10),
- View.SCROLL_CAPTURE_HINT_AUTO);
- targetQueue.add(target1);
-
- // callback 2, 20x20, hint=AUTO, responds after 5s from bg thread
- BackgroundTestCallback callback2 = new BackgroundTestCallback();
- callback2.setScrollBounds(new Rect(0, 0, 20, 20));
- callback2.setDelay(5000);
- ScrollCaptureTarget target2 = createTarget(
- callback2, new Rect(20, 30, 40, 50), new Point(10, 10),
- View.SCROLL_CAPTURE_HINT_AUTO);
- targetQueue.add(target2);
-
- // callback 3, 20x20, hint=INCLUDE, responds after 10s from bg thread
- BackgroundTestCallback callback3 = new BackgroundTestCallback();
- callback3.setScrollBounds(new Rect(0, 0, 20, 20));
- callback3.setDelay(10000);
- ScrollCaptureTarget target3 = createTarget(
- callback3, new Rect(20, 30, 40, 50), new Point(10, 10),
- View.SCROLL_CAPTURE_HINT_INCLUDE);
- targetQueue.add(target3);
-
- // callback 1 will be received
- // callback 2 & 3 will be ignored due to timeout
-
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertSame("Expected target1 as the result, due to timeouts of others", target1, result);
- assertEquals("result has wrong scroll bounds",
- new Rect(5, 5, 15, 15), result.getScrollBounds());
- assertEquals("callback1 should have been called",
- 1, callback1.getOnScrollCaptureSearchCount());
- assertEquals("callback2 should have been called",
- 1, callback2.getOnScrollCaptureSearchCount());
- assertEquals("callback3 should have been called",
- 1, callback3.getOnScrollCaptureSearchCount());
- }
-
- @Test(timeout = TEST_TIMEOUT_MS)
- public void testWithCallbackMultipleReplies() throws InterruptedException {
- // Calls response methods 3 times each
- RepeatingCaptureCallback callback1 = new RepeatingCaptureCallback(3);
- callback1.setScrollBounds(new Rect(2, 2, 18, 18));
- ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
- new Point(10, 10), View.SCROLL_CAPTURE_HINT_AUTO);
-
- FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
- callback2.setScrollBounds(new Rect(0, 0, 20, 20));
- ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
- new Point(10, 10), View.SCROLL_CAPTURE_HINT_AUTO);
-
- LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
- targetQueue.add(target1);
- targetQueue.add(target2);
-
- ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
- resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
- resolver.waitForResult();
-
- ScrollCaptureTarget result = mTargetConsumer.getLastValue();
- assertSame("Expected target2 as the result, due to hint=INCLUDE", target2, result);
- assertEquals("result has wrong scroll bounds",
- new Rect(0, 0, 20, 20), result.getScrollBounds());
- assertEquals("callback1 should have been called once",
- 1, callback1.getOnScrollCaptureSearchCount());
- assertEquals("callback2 should have been called once",
- 1, callback2.getOnScrollCaptureSearchCount());
- }
-
- private static class TargetConsumer implements Consumer<ScrollCaptureTarget> {
- volatile ScrollCaptureTarget mResult;
- int mAcceptCount;
-
- ScrollCaptureTarget getLastValue() {
- return mResult;
- }
-
- int acceptCount() {
- return mAcceptCount;
- }
-
- @Override
- public void accept(@Nullable ScrollCaptureTarget t) {
- mAcceptCount++;
- mResult = t;
- }
- }
-
- private void setupTargetView(View view, Rect localVisibleRect, int scrollCaptureHint) {
- view.setScrollCaptureHint(scrollCaptureHint);
- view.onVisibilityAggregated(true);
- // Treat any offset as padding, outset localVisibleRect on all sides and use this as
- // child bounds
- Rect bounds = new Rect(localVisibleRect);
- bounds.inset(-bounds.left, -bounds.top, bounds.left, bounds.top);
- view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom);
- view.onVisibilityAggregated(true);
- }
-
- private ScrollCaptureTarget createTarget(ScrollCaptureCallback callback, Rect localVisibleRect,
- Point positionInWindow, int scrollCaptureHint) {
- View mockView = new View(getTargetContext());
- return createTargetWithView(mockView, callback, localVisibleRect, positionInWindow,
- scrollCaptureHint);
- }
-
- private ScrollCaptureTarget createTargetWithView(View view, ScrollCaptureCallback callback,
- Rect localVisibleRect, Point positionInWindow, int scrollCaptureHint) {
- setupTargetView(view, localVisibleRect, scrollCaptureHint);
- return new ScrollCaptureTarget(view, localVisibleRect, positionInWindow, callback);
- }
-
-
- static class FakeRootView extends ViewGroup implements ViewParent {
- FakeRootView(Context context, int l, int t, int r, int b) {
- super(context);
- layout(l, t, r, b);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- }
- }
-
- static class FakeScrollCaptureCallback implements ScrollCaptureCallback {
- private Rect mScrollBounds;
- private long mDelayMillis;
- private int mOnScrollCaptureSearchCount;
-
- public int getOnScrollCaptureSearchCount() {
- return mOnScrollCaptureSearchCount;
- }
-
- @Override
- public void onScrollCaptureSearch(Consumer<Rect> onReady) {
- mOnScrollCaptureSearchCount++;
- run(() -> {
- Rect b = getScrollBounds();
- onReady.accept(b);
- });
- }
-
- @Override
- public void onScrollCaptureStart(ScrollCaptureSession session, Runnable onReady) {
- run(onReady);
- }
-
- @Override
- public void onScrollCaptureImageRequest(ScrollCaptureSession session, Rect captureArea) {
- run(() -> session.notifyBufferSent(0, captureArea));
- }
-
- @Override
- public void onScrollCaptureEnd(Runnable onReady) {
- run(onReady);
- }
-
- public void setScrollBounds(@Nullable Rect scrollBounds) {
- mScrollBounds = scrollBounds;
- }
-
- public void setDelay(long delayMillis) {
- mDelayMillis = delayMillis;
- }
-
- protected Rect getScrollBounds() {
- return mScrollBounds;
- }
-
- protected void run(Runnable r) {
- delay();
- r.run();
- }
-
- protected void delay() {
- if (mDelayMillis > 0) {
- try {
- Thread.sleep(mDelayMillis);
- } catch (InterruptedException e) {
- // Ignore
- }
- }
- }
- }
-
- static class RepeatingCaptureCallback extends FakeScrollCaptureCallback {
- private int mRepeatCount;
-
- RepeatingCaptureCallback(int repeatCount) {
- mRepeatCount = repeatCount;
- }
-
- protected void run(Runnable r) {
- delay();
- for (int i = 0; i < mRepeatCount; i++) {
- r.run();
- }
- }
- }
-
- /** Response to async calls on an arbitrary background thread */
- static class BackgroundTestCallback extends FakeScrollCaptureCallback {
- static int sCount = 0;
- private void runOnBackgroundThread(Runnable r) {
- final Runnable target = () -> {
- delay();
- r.run();
- };
- Thread t = new Thread(target);
- synchronized (BackgroundTestCallback.this) {
- sCount++;
- }
- t.setName("Background-Thread-" + sCount);
- t.start();
- }
-
- @Override
- protected void run(Runnable r) {
- runOnBackgroundThread(r);
- }
- }
-}
diff --git a/core/tests/coretests/src/android/view/TestScrollCaptureCallback.java b/core/tests/coretests/src/android/view/TestScrollCaptureCallback.java
new file mode 100644
index 0000000..1520c6e
--- /dev/null
+++ b/core/tests/coretests/src/android/view/TestScrollCaptureCallback.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 android.view;
+
+import static org.junit.Assert.*;
+
+import android.graphics.Rect;
+import android.os.CancellationSignal;
+
+import androidx.annotation.NonNull;
+
+import java.util.function.Consumer;
+
+class TestScrollCaptureCallback implements ScrollCaptureCallback {
+ private Consumer<Rect> mSearchConsumer;
+ private Runnable mStartOnReady;
+ private Consumer<Rect> mImageOnComplete;
+ private Runnable mOnEndReady;
+ private volatile int mModCount;
+
+ @Override
+ public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+ @NonNull Consumer<Rect> onReady) {
+ mSearchConsumer = onReady;
+ mModCount++;
+ }
+
+ @Override
+ public void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Runnable onReady) {
+ mStartOnReady = onReady;
+ mModCount++;
+ }
+
+ @Override
+ public void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+ @NonNull Consumer<Rect> onComplete) {
+ mImageOnComplete = onComplete;
+ mModCount++;
+ }
+
+ @Override
+ public void onScrollCaptureEnd(@NonNull Runnable onReady) {
+ mOnEndReady = onReady;
+ }
+
+ void completeSearchRequest(Rect scrollBounds) {
+ assertNotNull("Did not receive search request", mSearchConsumer);
+ mSearchConsumer.accept(scrollBounds);
+ mModCount++;
+ }
+
+ void verifyZeroInteractions() {
+ assertEquals("Expected zero interactions", 0, mModCount);
+ }
+
+ void completeStartRequest() {
+ assertNotNull("Did not receive start request", mStartOnReady);
+ mStartOnReady.run();
+ }
+
+ void completeImageRequest(Rect captured) {
+ assertNotNull("Did not receive image request", mImageOnComplete);
+ mImageOnComplete.accept(captured);
+ }
+
+ void completeEndRequest() {
+ assertNotNull("Did not receive end request", mOnEndReady);
+ mOnEndReady.run();
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
index 3af0533..41cd4c5 100644
--- a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
@@ -19,7 +19,9 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.testng.AssertJUnit.assertSame;
@@ -27,19 +29,20 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.CancellationSignal;
import android.platform.test.annotations.Presubmit;
+import androidx.annotation.NonNull;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
-import java.util.LinkedList;
-import java.util.Queue;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Exercises Scroll Capture search in {@link ViewGroup}.
@@ -50,10 +53,7 @@
@RunWith(MockitoJUnitRunner.class)
public class ViewGroupScrollCaptureTest {
- @Mock
- ScrollCaptureCallback mMockCallback;
- @Mock
- ScrollCaptureCallback mMockCallback2;
+ private static final Executor DIRECT_EXECUTOR = Runnable::run;
/** Make sure the hint flags are saved and loaded correctly. */
@Test
@@ -103,25 +103,24 @@
public void testDispatchScrollCaptureSearch_noCallback_hintAuto() throws Exception {
final Context context = getInstrumentation().getContext();
final MockViewGroup viewGroup = new MockViewGroup(context, 0, 0, 200, 200);
+ TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
// When system internal scroll capture is requested, this callback is returned.
- viewGroup.setScrollCaptureCallbackInternalForTest(mMockCallback);
+ viewGroup.setScrollCaptureCallbackInternalForTest(callback);
Rect localVisibleRect = new Rect(0, 0, 200, 200);
Point windowOffset = new Point();
- LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
// Dispatch
- viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
-
- // Verify the system checked for fallback support
- viewGroup.assertDispatchScrollCaptureCount(1);
- viewGroup.assertLastDispatchScrollCaptureArgs(localVisibleRect, windowOffset);
+ viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+ callback.completeSearchRequest(new Rect(1, 2, 3, 4));
+ assertTrue(results.isComplete());
// Verify the target is as expected.
- assertEquals(1, targetList.size());
- ScrollCaptureTarget target = targetList.get(0);
- assertSame("Target has the wrong callback", mMockCallback, target.getCallback());
+ ScrollCaptureTarget target = results.getTopResult();
+ assertNotNull("Target not found", target);
+ assertSame("Target has the wrong callback", callback, target.getCallback());
assertSame("Target has the wrong View", viewGroup, target.getContainingView());
assertEquals("Target hint is incorrect", View.SCROLL_CAPTURE_HINT_AUTO,
target.getContainingView().getScrollCaptureHint());
@@ -139,18 +138,22 @@
final MockViewGroup viewGroup =
new MockViewGroup(context, 0, 0, 200, 200, View.SCROLL_CAPTURE_HINT_EXCLUDE);
+ TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
+
// When system internal scroll capture is requested, this callback is returned.
- viewGroup.setScrollCaptureCallbackInternalForTest(mMockCallback);
+ viewGroup.setScrollCaptureCallbackInternalForTest(callback);
Rect localVisibleRect = new Rect(0, 0, 200, 200);
Point windowOffset = new Point();
- LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
+ assertTrue(results.isComplete());
// Dispatch
- viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
+ viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+ callback.verifyZeroInteractions();
// Verify the results.
- assertEquals("Target list size should be zero.", 0, targetList.size());
+ assertTrue("Results should be empty.", results.isEmpty());
}
/**
@@ -164,27 +167,34 @@
final Context context = getInstrumentation().getContext();
MockViewGroup viewGroup = new MockViewGroup(context, 0, 0, 200, 200);
+ TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
+ TestScrollCaptureCallback callback2 = new TestScrollCaptureCallback();
+
// With an already provided scroll capture callback
- viewGroup.setScrollCaptureCallback(mMockCallback);
+ viewGroup.setScrollCaptureCallback(callback);
// When system internal scroll capture is requested, this callback is returned.
- viewGroup.setScrollCaptureCallbackInternalForTest(mMockCallback);
+ viewGroup.setScrollCaptureCallbackInternalForTest(callback2);
Rect localVisibleRect = new Rect(0, 0, 200, 200);
Point windowOffset = new Point();
- LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
// Dispatch to the ViewGroup
- viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
-
- // Confirm that framework support was not requested,
- // because this view already had a callback set.
- viewGroup.assertCreateScrollCaptureCallbackInternalCount(0);
+ viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+ callback.completeSearchRequest(new Rect(1, 2, 3, 4));
// Verify the target is as expected.
- assertEquals(1, targetList.size());
- ScrollCaptureTarget target = targetList.get(0);
- assertSame("Target has the wrong callback", mMockCallback, target.getCallback());
+ assertFalse(results.isEmpty());
+ assertTrue(results.isComplete());
+
+ // internal framework callback was not requested
+ callback2.verifyZeroInteractions();
+
+ ScrollCaptureTarget target = results.getTopResult();
+
+ assertNotNull("Target not found", target);
+ assertSame("Target has the wrong callback", callback, target.getCallback());
assertSame("Target has the wrong View", viewGroup, target.getContainingView());
assertEquals("Target hint is incorrect", View.SCROLL_CAPTURE_HINT_AUTO,
target.getContainingView().getScrollCaptureHint());
@@ -201,22 +211,22 @@
final Context context = getInstrumentation().getContext();
MockViewGroup viewGroup =
new MockViewGroup(context, 0, 0, 200, 200, View.SCROLL_CAPTURE_HINT_EXCLUDE);
+
+ TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
+
// With an already provided scroll capture callback
- viewGroup.setScrollCaptureCallback(mMockCallback);
+ viewGroup.setScrollCaptureCallback(callback);
Rect localVisibleRect = new Rect(0, 0, 200, 200);
Point windowOffset = new Point();
- LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+ ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
// Dispatch to the ViewGroup itself
- viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
-
- // Confirm that framework support was not requested, because this view is excluded.
- // (And because this view has a callback set.)
- viewGroup.assertCreateScrollCaptureCallbackInternalCount(0);
+ viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+ callback.verifyZeroInteractions();
// Has callback, but hint=excluded, so excluded.
- assertTrue(targetList.isEmpty());
+ assertNull(results.getTopResult());
}
/**
@@ -252,37 +262,43 @@
// | | |
// +---------------+----------+ (200,200)
- // View 1 is clipped and not visible.
+ // View 1 is fully clipped and not visible.
final MockView view1 = new MockView(context, 0, 0, 200, 25);
viewGroup.addView(view1);
- // View 2 is partially visible.
+ // View 2 is partially visible. (75x75)
final MockView view2 = new MockView(context, 0, 25, 150, 100);
viewGroup.addView(view2);
- // View 3 is partially visible.
+ TestScrollCaptureCallback callback1 = new TestScrollCaptureCallback();
+
+ // View 3 is partially visible (175x50)
// Pretend View3 can scroll by having framework provide fallback support
final MockView view3 = new MockView(context, 0, 100, 200, 200);
// When system internal scroll capture is requested for this view, return this callback.
- view3.setScrollCaptureCallbackInternalForTest(mMockCallback);
+ view3.setScrollCaptureCallbackInternalForTest(callback1);
viewGroup.addView(view3);
// View 4 is invisible and should be ignored.
final MockView view4 = new MockView(context, 150, 25, 200, 100, View.INVISIBLE);
viewGroup.addView(view4);
- // View 4 is invisible and should be ignored.
+ TestScrollCaptureCallback callback2 = new TestScrollCaptureCallback();
+
+ // View 5 is partially visible and explicitly included via flag. (25x50)
final MockView view5 = new MockView(context, 150, 100, 200, 200);
- // When system internal scroll capture is requested for this view, return this callback.
- view5.setScrollCaptureCallback(mMockCallback2);
+ view5.setScrollCaptureCallback(callback2);
view5.setScrollCaptureHint(View.SCROLL_CAPTURE_HINT_INCLUDE);
viewGroup.addView(view5);
// Where targets are added
- final LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+ final ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
// Dispatch to the ViewGroup
- viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
+ viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+ callback1.completeSearchRequest(new Rect(0, 0, 200, 100));
+ callback2.completeSearchRequest(new Rect(0, 0, 50, 100));
+ assertTrue(results.isComplete());
// View 1 is entirely clipped by the parent and not visible, dispatch
// skips this view entirely.
@@ -317,18 +333,14 @@
view5.assertCreateScrollCaptureCallbackInternalCount(0);
// 2 views should have been returned, view3 & view5
- assertEquals(2, targetList.size());
+ assertFalse(results.isEmpty());
+ assertTrue(results.isComplete());
- ScrollCaptureTarget target = targetList.get(0);
- assertSame("First target has the wrong View", view3, target.getContainingView());
- assertSame("First target has the wrong callback", mMockCallback, target.getCallback());
- assertEquals("First target hint is incorrect", View.SCROLL_CAPTURE_HINT_AUTO,
- target.getContainingView().getScrollCaptureHint());
-
- target = targetList.get(1);
- assertSame("Second target has the wrong View", view5, target.getContainingView());
- assertSame("Second target has the wrong callback", mMockCallback2, target.getCallback());
- assertEquals("Second target hint is incorrect", View.SCROLL_CAPTURE_HINT_INCLUDE,
+ ScrollCaptureTarget target = results.getTopResult();
+ assertNotNull("Target not found", target);
+ assertSame("Result is the wrong View", view5, target.getContainingView());
+ assertSame("Result is the wrong callback", callback2, target.getCallback());
+ assertEquals("First target hint is incorrect", View.SCROLL_CAPTURE_HINT_INCLUDE,
target.getContainingView().getScrollCaptureHint());
}
@@ -371,7 +383,7 @@
}
void assertCreateScrollCaptureCallbackInternalCount(int count) {
- assertEquals("Unexpected number of calls to createScrollCaptureCallackInternal",
+ assertEquals("Unexpected number of calls to createScrollCaptureCallbackInternal",
count, mCreateScrollCaptureCallbackInternalCount);
}
@@ -385,11 +397,11 @@
@Override
public void dispatchScrollCaptureSearch(Rect localVisibleRect, Point windowOffset,
- Queue<ScrollCaptureTarget> targets) {
+ Consumer<ScrollCaptureTarget> results) {
mDispatchScrollCaptureSearchNumCalls++;
mDispatchScrollCaptureSearchLastLocalVisibleRect = new Rect(localVisibleRect);
mDispatchScrollCaptureSearchLastWindowOffset = new Point(windowOffset);
- super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets);
+ super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results);
}
@Override
@@ -401,13 +413,31 @@
}
}
+ static class CallbackStub implements ScrollCaptureCallback {
+
+ @Override
+ public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+ @NonNull Consumer<Rect> onReady) {
+ }
+
+ @Override
+ public void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Runnable onReady) {
+ }
+
+ @Override
+ public void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+ @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+ Consumer<Rect> onComplete) {
+ }
+
+ @Override
+ public void onScrollCaptureEnd(@NonNull Runnable onReady) {
+ }
+ };
+
public static final class MockViewGroup extends ViewGroup {
private ScrollCaptureCallback mInternalCallback;
- private int mDispatchScrollCaptureSearchNumCalls;
- private Rect mDispatchScrollCaptureSearchLastLocalVisibleRect;
- private Point mDispatchScrollCaptureSearchLastWindowOffset;
- private int mCreateScrollCaptureCallbackInternalCount;
-
MockViewGroup(Context context) {
this(context, /* left */ 0, /* top */0, /* right */ 0, /* bottom */0);
@@ -428,16 +458,10 @@
mInternalCallback = internal;
}
- void assertDispatchScrollCaptureSearchCount(int count) {
- assertEquals("Unexpected number of calls to dispatchScrollCaptureSearch",
- count, mDispatchScrollCaptureSearchNumCalls);
- }
-
@Override
@Nullable
public ScrollCaptureCallback createScrollCaptureCallbackInternal(Rect localVisibleRect,
Point offsetInWindow) {
- mCreateScrollCaptureCallbackInternalCount++;
return mInternalCallback;
}
@@ -445,36 +469,5 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// We don't layout this view.
}
-
- void assertDispatchScrollCaptureCount(int count) {
- assertEquals(count, mDispatchScrollCaptureSearchNumCalls);
- }
-
- void assertLastDispatchScrollCaptureArgs(Rect localVisibleRect, Point windowOffset) {
- assertEquals("arg localVisibleRect to dispatchScrollCaptureCallback was incorrect.",
- localVisibleRect, mDispatchScrollCaptureSearchLastLocalVisibleRect);
- assertEquals("arg windowOffset to dispatchScrollCaptureCallback was incorrect.",
- windowOffset, mDispatchScrollCaptureSearchLastWindowOffset);
- }
- void assertCreateScrollCaptureCallbackInternalCount(int count) {
- assertEquals("Unexpected number of calls to createScrollCaptureCallackInternal",
- count, mCreateScrollCaptureCallbackInternalCount);
- }
-
- void reset() {
- mDispatchScrollCaptureSearchNumCalls = 0;
- mDispatchScrollCaptureSearchLastWindowOffset = null;
- mDispatchScrollCaptureSearchLastLocalVisibleRect = null;
- mCreateScrollCaptureCallbackInternalCount = 0;
- }
-
- @Override
- public void dispatchScrollCaptureSearch(Rect localVisibleRect, Point windowOffset,
- Queue<ScrollCaptureTarget> targets) {
- mDispatchScrollCaptureSearchNumCalls++;
- mDispatchScrollCaptureSearchLastLocalVisibleRect = new Rect(localVisibleRect);
- mDispatchScrollCaptureSearchLastWindowOffset = new Point(windowOffset);
- super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets);
- }
}
}
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index c67174f..7746bc2 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -207,7 +207,7 @@
final CountDownLatch latch = new CountDownLatch(1);
mViewRootImpl.handleScrollCaptureRequest(new IScrollCaptureCallbacks.Default() {
@Override
- public void onUnavailable() {
+ public void onScrollCaptureResponse(ScrollCaptureResponse response) {
latch.countDown();
}
});
@@ -220,6 +220,37 @@
}
/**
+ * Ensure scroll capture request handles a ViewRootImpl with no view tree.
+ */
+ @Test
+ public void requestScrollCapture_timeout() {
+ final View view = new View(mContext);
+ view.setScrollCaptureCallback(new TestScrollCaptureCallback()); // Does nothing
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ WindowManager.LayoutParams wmlp =
+ new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+ // Set a fake token to bypass 'is your activity running' check
+ wmlp.token = new Binder();
+ view.setLayoutParams(wmlp);
+ mViewRootImpl.setView(view, wmlp, null);
+ });
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ mViewRootImpl.setScrollCaptureRequestTimeout(100);
+ mViewRootImpl.handleScrollCaptureRequest(new IScrollCaptureCallbacks.Default() {
+ @Override
+ public void onScrollCaptureResponse(ScrollCaptureResponse response) {
+ latch.countDown();
+ }
+ });
+ try {
+ if (!latch.await(2500, TimeUnit.MILLISECONDS)) {
+ fail("requestScrollCapture timeout did not occur");
+ }
+ } catch (InterruptedException e) { /* ignore */ }
+ }
+
+ /**
* When window doesn't have focus, keys should be dropped.
*/
@Test
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
index 4680a64..ddb6729 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
@@ -17,14 +17,17 @@
import static com.google.common.truth.Truth.assertThat;
+import android.app.assist.ActivityId;
import android.content.ComponentName;
+import android.os.Binder;
+import android.os.IBinder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
- * Unit test for {@link ContentCaptureEvent}.
+ * Unit test for {@link ContentCaptureContext}.
*
* <p>To run it:
* {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureContextTest}
@@ -35,13 +38,17 @@
@Test
public void testConstructorAdditionalFlags() {
final ComponentName componentName = new ComponentName("component", "name");
+ final IBinder token = new Binder();
final ContentCaptureContext ctx = new ContentCaptureContext(/* clientContext= */ null,
- componentName, /* taskId= */ 666, /* displayId= */ 42, /* flags= */ 1);
+ new ActivityId(/* taskId= */ 666, token), componentName, /* displayId= */
+ 42, /* flags= */ 1);
final ContentCaptureContext newCtx = new ContentCaptureContext(ctx, /* extraFlags= */ 2);
assertThat(newCtx.getFlags()).isEqualTo(3);
-
assertThat(newCtx.getActivityComponent()).isEqualTo(componentName);
- assertThat(newCtx.getTaskId()).isEqualTo(666);
+ ActivityId activityId = newCtx.getActivityId();
+ assertThat(activityId).isNotNull();
+ assertThat(activityId.getTaskId()).isEqualTo(666);
+ assertThat(activityId.getToken()).isEqualTo(token);
assertThat(newCtx.getDisplayId()).isEqualTo(42);
assertThat(newCtx.getExtras()).isNull();
assertThat(newCtx.getLocusId()).isNull();
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 9cac7e7..ff728d6 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -77,6 +77,7 @@
* bit FrameworksCoreTests:com.android.internal.os.BatteryStatsCpuTimesTest
*/
@SmallTest
+@SkipPresubmit("b/180015146")
@RunWith(AndroidJUnit4.class)
public class BatteryStatsCpuTimesTest {
@Mock
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
new file mode 100644
index 0000000..263daf0
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.Process;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BatteryStatsHistoryIteratorTest {
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
+ @Test
+ public void testIterator() {
+ MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+ batteryStats.setRecordAllHistoryLocked(true);
+ batteryStats.forceRecordAllHistory();
+
+ mStatsRule.setTime(1000, 1000);
+ batteryStats.setNoAutoReset(true);
+
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
+ 1_000_000, 1_000_000);
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000,
+ 2_000_000, 2_000_000);
+
+ batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
+ batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
+
+ final BatteryStatsHistoryIterator iterator =
+ batteryStats.createBatteryStatsHistoryIterator();
+
+ BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE,
+ null, 0, 3_600_000, 90, 1_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+ null, 0, 3_600_000, 90, 1_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+ null, 0, 2_400_000, 80, 2_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+ null, 0, 2_400_000, 80, 2_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE,
+ BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START,
+ "foo", APP_UID, 2_400_000, 80, 3_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE,
+ BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH,
+ "foo", APP_UID, 2_400_000, 80, 3_001_000);
+
+ assertThat(iterator.next(item)).isFalse();
+ }
+
+ private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
+ String tag, int uid, int batteryChargeUah, int batteryLevel,
+ long elapsedTimeMs) {
+ assertThat(item.cmd).isEqualTo(command);
+ assertThat(item.eventCode).isEqualTo(eventCode);
+ if (tag == null) {
+ assertThat(item.eventTag).isNull();
+ } else {
+ assertThat(item.eventTag.string).isEqualTo(tag);
+ assertThat(item.eventTag.uid).isEqualTo(uid);
+ }
+ assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah);
+ assertThat(item.batteryLevel).isEqualTo(batteryLevel);
+
+ assertThat(item.time).isEqualTo(elapsedTimeMs);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index 4b37dd2..24baa93 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -73,6 +73,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testUpdateProcStateCpuTimes() {
mBatteryStatsImpl.setOnBatteryInternal(true);
mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
@@ -230,6 +231,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testCopyFromAllUidsCpuTimes() {
mBatteryStatsImpl.setOnBatteryInternal(false);
mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 6652c64..931611e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -295,6 +295,7 @@
}
@SmallTest
+ @SkipPresubmit("b/180015146")
public void testAlarmStartAndFinishLocked() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
@@ -332,6 +333,7 @@
}
@SmallTest
+ @SkipPresubmit("b/180015146")
public void testAlarmStartAndFinishLocked_workSource() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index 3b27f18..dd814e6 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -56,6 +56,7 @@
}
@SmallTest
+ @SkipPresubmit("b/180015146")
public void testEndSampleAndContinueWhenTimeOrCountDecreases() throws Exception {
final MockClocks clocks = new MockClocks();
final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index b819d9e..74c37ada 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -30,6 +30,7 @@
BatteryStatsDualTimerTest.class,
BatteryStatsDurationTimerTest.class,
BatteryStatsHelperTest.class,
+ BatteryStatsHistoryIteratorTest.class,
BatteryStatsHistoryTest.class,
BatteryStatsImplTest.class,
BatteryStatsNoteTest.class,
@@ -40,6 +41,7 @@
BatteryStatsTimeBaseTest.class,
BatteryStatsTimerTest.class,
BatteryStatsUidTest.class,
+ BatteryUsageStatsProviderTest.class,
BatteryUsageStatsTest.class,
BatteryStatsUserLifecycleTests.class,
BluetoothPowerCalculatorTest.class,
@@ -71,9 +73,9 @@
UserPowerCalculatorTest.class,
VideoPowerCalculatorTest.class,
WakelockPowerCalculatorTest.class,
+ WifiPowerCalculatorTest.class,
com.android.internal.power.MeasuredEnergyStatsTest.class
})
public class BatteryStatsTests {
-}
-
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
index e7a1bca..e90bcb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
@@ -78,6 +78,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testNoCpuDataForRemovedUser() throws Exception {
mIam.startUserInBackground(mTestUserId);
waitUntilTrue("No uids for started user " + mTestUserId,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
new file mode 100644
index 0000000..0f59143
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.Parcel;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryUsageStatsProviderTest {
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+ private static final long MINUTE_IN_MS = 60 * 1000;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
+ @Test
+ public void test_getBatteryUsageStats() {
+ BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+ batteryStats.noteActivityResumedLocked(APP_UID,
+ 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
+ batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_TOP,
+ 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
+ batteryStats.noteActivityPausedLocked(APP_UID,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+ batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_SERVICE,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+ batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+ 40 * MINUTE_IN_MS, 40 * MINUTE_IN_MS);
+
+ Context context = InstrumentationRegistry.getContext();
+ BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, batteryStats);
+
+ final BatteryUsageStats batteryUsageStats =
+ provider.getBatteryUsageStats(BatteryUsageStatsQuery.DEFAULT);
+
+ final List<UidBatteryConsumer> uidBatteryConsumers =
+ batteryUsageStats.getUidBatteryConsumers();
+ final UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(0);
+ assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
+ .isEqualTo(20 * MINUTE_IN_MS);
+ assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
+ .isEqualTo(10 * MINUTE_IN_MS);
+ }
+
+ @Test
+ public void testWriteAndReadHistory() {
+ MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+ batteryStats.setRecordAllHistoryLocked(true);
+ batteryStats.forceRecordAllHistory();
+
+ batteryStats.setNoAutoReset(true);
+
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
+ 1_000_000, 1_000_000);
+
+ batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
+ batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
+
+ Context context = InstrumentationRegistry.getContext();
+ BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, batteryStats);
+
+ final BatteryUsageStats batteryUsageStats =
+ provider.getBatteryUsageStats(
+ new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
+
+ Parcel in = Parcel.obtain();
+ batteryUsageStats.writeToParcel(in, 0);
+ final byte[] bytes = in.marshall();
+
+ Parcel out = Parcel.obtain();
+ out.unmarshall(bytes, 0, bytes.length);
+ out.setDataPosition(0);
+
+ BatteryUsageStats unparceled = BatteryUsageStats.CREATOR.createFromParcel(out);
+
+ final BatteryStatsHistoryIterator iterator =
+ unparceled.iterateBatteryStatsHistory();
+ BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE,
+ null, 0, 3_600_000, 90, 1_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+ null, 0, 3_600_000, 90, 1_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+ null, 0, 3_600_000, 90, 2_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE,
+ BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START,
+ "foo", APP_UID, 3_600_000, 90, 3_000_000);
+
+ assertThat(iterator.next(item)).isTrue();
+ assertHistoryItem(item,
+ BatteryStats.HistoryItem.CMD_UPDATE,
+ BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH,
+ "foo", APP_UID, 3_600_000, 90, 3_001_000);
+
+ assertThat(iterator.next(item)).isFalse();
+ }
+
+ private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
+ String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) {
+ assertThat(item.cmd).isEqualTo(command);
+ assertThat(item.eventCode).isEqualTo(eventCode);
+ if (tag == null) {
+ assertThat(item.eventTag).isNull();
+ } else {
+ assertThat(item.eventTag.string).isEqualTo(tag);
+ assertThat(item.eventTag.uid).isEqualTo(uid);
+ }
+ assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah);
+ assertThat(item.batteryLevel).isEqualTo(batteryLevel);
+
+ assertThat(item.time).isEqualTo(elapsedTimeMs);
+ }
+}
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 355ac6d..23ea508 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -35,6 +35,7 @@
import java.util.List;
@SmallTest
+@SkipPresubmit("b/180015146")
@RunWith(AndroidJUnit4.class)
public class BatteryUsageStatsTest {
@@ -66,33 +67,36 @@
final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
- final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1);
- builder.setDischargePercentage(20);
- builder.setDischargedPowerRange(1000, 2000);
+ final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1)
+ .setDischargePercentage(20)
+ .setDischargedPowerRange(1000, 2000);
- final UidBatteryConsumer.Builder uidBatteryConsumerBuilder =
- builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
- uidBatteryConsumerBuilder.setPackageWithHighestDrain("foo");
- uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 300);
- uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 400);
- uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
- BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500);
- uidBatteryConsumerBuilder.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, 600);
- uidBatteryConsumerBuilder.setUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700);
- uidBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);
+ builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid)
+ .setPackageWithHighestDrain("foo")
+ .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000)
+ .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, 2000)
+ .setConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_USAGE, 300)
+ .setConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_CPU, 400)
+ .setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500)
+ .setUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU, 600)
+ .setUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700)
+ .setUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);
- final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
- builder.getOrCreateSystemBatteryConsumerBuilder(
- SystemBatteryConsumer.DRAIN_TYPE_CAMERA);
- systemBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 10100);
- systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
- BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200);
- systemBatteryConsumerBuilder.setUsageDurationMillis(
- BatteryConsumer.TIME_COMPONENT_CPU, 10300);
- systemBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
+ builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_CAMERA)
+ .setConsumedPower(
+ BatteryConsumer.POWER_COMPONENT_CPU, 10100)
+ .setConsumedPowerForCustomComponent(
+ BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200)
+ .setUsageDurationMillis(
+ BatteryConsumer.TIME_COMPONENT_CPU, 10300)
+ .setUsageDurationForCustomComponentMillis(
+ BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
return builder.build();
}
@@ -108,6 +112,10 @@
for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
if (uidBatteryConsumer.getUid() == 2000) {
assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo("foo");
+ assertThat(uidBatteryConsumer.getTimeInStateMs(
+ UidBatteryConsumer.STATE_FOREGROUND)).isEqualTo(1000);
+ assertThat(uidBatteryConsumer.getTimeInStateMs(
+ UidBatteryConsumer.STATE_BACKGROUND)).isEqualTo(2000);
assertThat(uidBatteryConsumer.getConsumedPower(
BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
assertThat(uidBatteryConsumer.getConsumedPower(
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 e559471..f6aa08b 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -43,6 +43,7 @@
.setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0);
@Test
+ @SkipPresubmit("b/180015146")
public void testTimerBasedModel() {
setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID)
.getOrCreateBluetoothControllerActivityLocked(),
@@ -73,6 +74,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testReportedPowerBasedModel() {
setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID)
.getOrCreateBluetoothControllerActivityLocked(),
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index a80f5a0..4fe7d70 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -382,6 +382,7 @@
}
@Test
+ @SkipPresubmit("b/180015146 flakey")
public void testCpuFreqTimes_stateFgService() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
Log.w(TAG, "Skipping " + testName.getMethodName()
@@ -514,6 +515,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testCpuFreqTimes_trackingDisabled() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
Log.w(TAG, "Skipping " + testName.getMethodName()
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 9cf0d37..e691beb 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -92,6 +92,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testTimerBasedModel() {
when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
diff --git a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
index a4ea892..f298f59 100644
--- a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
@@ -42,6 +42,7 @@
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
@Test
+ @SkipPresubmit("b/180015146")
public void testMeasuredEnergyCopiedIntoBatteryConsumers() {
final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
SparseLongArray uidEnergies = new SparseLongArray();
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
index 7dca0cb..177f348 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
@@ -87,6 +87,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testThrottler() throws Exception {
mReader = new KernelCpuUidUserSysTimeReader(
new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), true);
diff --git a/core/tests/coretests/src/com/android/internal/os/SkipPresubmit.java b/core/tests/coretests/src/com/android/internal/os/SkipPresubmit.java
new file mode 100644
index 0000000..d03ed66
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SkipPresubmit.java
@@ -0,0 +1,30 @@
+/*
+ * 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.os;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Annotation to skip a test from TEST_MAPPING presubmit. */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface SkipPresubmit {
+ /** The optional reason why the test is ignored. */
+ String value() default "";
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index dfbf28b..b5282e9 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -78,6 +78,7 @@
}
@Test
+ @SkipPresubmit("b/180015146")
public void testPowerProfileBasedModel() {
when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
new file mode 100644
index 0000000..e100545
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.os;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.NetworkCapabilities;
+import android.net.NetworkStats;
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.os.WorkSource;
+import android.os.connectivity.WifiActivityEnergyInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WifiPowerCalculatorTest {
+ private static final double PRECISION = 0.00001;
+
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE, 360.0)
+ .setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX, 480.0)
+ .setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX, 720.0)
+ .setAveragePower(PowerProfile.POWER_WIFI_ON, 360.0)
+ .setAveragePower(PowerProfile.POWER_WIFI_SCAN, 480.0)
+ .setAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, 720.0)
+ .setAveragePower(PowerProfile.POWER_WIFI_ACTIVE, 1080.0);
+
+ @Test
+ public void testPowerControllerBasedModel() {
+ BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+ batteryStats.noteNetworkInterfaceForTransports("wifi",
+ new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+
+ NetworkStats networkStats = new NetworkStats(10000, 1)
+ .insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
+ .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
+ mStatsRule.setNetworkStats(networkStats);
+
+ WifiActivityEnergyInfo energyInfo = new WifiActivityEnergyInfo(10000,
+ WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
+
+ batteryStats.updateWifiState(energyInfo, 1000, 1000);
+
+ WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(calculator);
+
+ UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ .isEqualTo(1423);
+ assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isWithin(PRECISION).of(0.2214666);
+
+ SystemBatteryConsumer systemConsumer =
+ mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
+ assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ .isEqualTo(5577);
+ assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isWithin(PRECISION).of(0.645200);
+ }
+
+ @Test
+ public void testTimerBasedModel() {
+ BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+ batteryStats.noteNetworkInterfaceForTransports("wifi",
+ new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+
+ NetworkStats networkStats = new NetworkStats(10000, 1)
+ .insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
+ .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
+ mStatsRule.setNetworkStats(networkStats);
+
+ batteryStats.noteWifiScanStartedLocked(APP_UID, 1000, 1000);
+ batteryStats.noteWifiScanStoppedLocked(APP_UID, 2000, 2000);
+ batteryStats.noteWifiRunningLocked(new WorkSource(APP_UID), 3000, 3000);
+ batteryStats.noteWifiStoppedLocked(new WorkSource(APP_UID), 4000, 4000);
+ batteryStats.noteWifiRunningLocked(new WorkSource(Process.WIFI_UID), 1111, 2222);
+ batteryStats.noteWifiStoppedLocked(new WorkSource(Process.WIFI_UID), 3333, 4444);
+
+ // Don't pass WifiActivityEnergyInfo, making WifiPowerCalculator rely exclusively
+ // on the packet counts.
+ batteryStats.updateWifiState(/* energyInfo */ null, 1000, 1000);
+
+ WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(calculator);
+
+ UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ .isEqualTo(1000);
+ assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isWithin(PRECISION).of(0.8231573);
+
+ SystemBatteryConsumer systemConsumer =
+ mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
+ assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+ .isEqualTo(2222);
+ assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isWithin(PRECISION).of(0.8759216);
+ }
+}
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 5fd5a78..d217bce 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -81,11 +81,11 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- stats.updateCustomBucket(0, 50, true);
- stats.updateCustomBucket(1, 60, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ stats.updateCustomBucket(0, 50);
+ stats.updateCustomBucket(1, 60);
final MeasuredEnergyStats newStats = MeasuredEnergyStats.createFromTemplate(stats);
@@ -114,11 +114,11 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- stats.updateCustomBucket(0, 50, true);
- stats.updateCustomBucket(1, 60, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ stats.updateCustomBucket(0, 50);
+ stats.updateCustomBucket(1, 60);
final Parcel parcel = Parcel.obtain();
stats.writeToParcel(parcel);
@@ -149,11 +149,11 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- stats.updateCustomBucket(0, 50, true);
- stats.updateCustomBucket(1, 60, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ stats.updateCustomBucket(0, 50);
+ stats.updateCustomBucket(1, 60);
final Parcel parcel = Parcel.obtain();
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -185,17 +185,17 @@
final MeasuredEnergyStats template
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
- template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- template.updateCustomBucket(0, 50, true);
+ template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+ template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ template.updateCustomBucket(0, 50);
final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 7, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 63, true);
- stats.updateCustomBucket(0, 315, true);
- stats.updateCustomBucket(1, 316, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 7);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 63);
+ stats.updateCustomBucket(0, 315);
+ stats.updateCustomBucket(1, 316);
final Parcel parcel = Parcel.obtain();
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -243,8 +243,8 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
// Accumulate energy in one bucket and one custom bucket, the rest should be zero
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
- stats.updateCustomBucket(1, 60, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200);
+ stats.updateCustomBucket(1, 60);
// Let's try parcelling with including zeros
final Parcel includeZerosParcel = Parcel.obtain();
@@ -305,11 +305,11 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- stats.updateCustomBucket(0, 50, true);
- stats.updateCustomBucket(1, 60, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ stats.updateCustomBucket(0, 50);
+ stats.updateCustomBucket(1, 60);
final Parcel parcel = Parcel.obtain();
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -331,14 +331,14 @@
final MeasuredEnergyStats template
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
- template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- template.updateCustomBucket(0, 50, true);
+ template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+ template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ template.updateCustomBucket(0, 50);
final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 0L, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 7L, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 0L);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 7L);
final Parcel parcel = Parcel.obtain();
MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -369,14 +369,14 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_DOZE, 30, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_DOZE, 30);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
- stats.updateCustomBucket(0, 50, true);
- stats.updateCustomBucket(1, 60, true);
- stats.updateCustomBucket(0, 3, true);
+ stats.updateCustomBucket(0, 50);
+ stats.updateCustomBucket(1, 60);
+ stats.updateCustomBucket(0, 3);
assertEquals(15, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
assertEquals(ENERGY_DATA_UNAVAILABLE,
@@ -409,10 +409,10 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3);
- stats.updateCustomBucket(0, 50, true);
- stats.updateCustomBucket(1, 60, true);
- stats.updateCustomBucket(2, 13, true);
- stats.updateCustomBucket(1, 70, true);
+ stats.updateCustomBucket(0, 50);
+ stats.updateCustomBucket(1, 60);
+ stats.updateCustomBucket(2, 13);
+ stats.updateCustomBucket(1, 70);
final long[] output = stats.getAccumulatedCustomBucketEnergies();
assertEquals(3, output.length);
@@ -449,11 +449,11 @@
final MeasuredEnergyStats stats
= new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
- stats.updateCustomBucket(0, 50, true);
- stats.updateCustomBucket(1, 60, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+ stats.updateCustomBucket(0, 50);
+ stats.updateCustomBucket(1, 60);
MeasuredEnergyStats.resetIfNotNull(stats);
// All energy should be reset to 0
@@ -471,10 +471,10 @@
}
// Values should increase as usual.
- stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 70, true);
+ stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 70);
assertEquals(70L, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
- stats.updateCustomBucket(1, 12, true);
+ stats.updateCustomBucket(1, 12);
assertEquals(12L, stats.getAccumulatedCustomBucketEnergy(1));
}
diff --git a/core/tests/devicestatetests/Android.bp b/core/tests/devicestatetests/Android.bp
index f7b5932..7748de5 100644
--- a/core/tests/devicestatetests/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -28,6 +28,7 @@
static_libs: [
"androidx.test.rules",
"frameworks-base-testutils",
+ "mockito-target-minus-junit4",
],
libs: ["android.test.runner"],
platform_apis: true,
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
new file mode 100644
index 0000000..dcef0a7
--- /dev/null
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.hardware.devicestate;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for {@link DeviceStateInfo}.
+ * <p/>
+ * Run with <code>atest DeviceStateInfoTest</code>.
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+public final class DeviceStateInfoTest {
+ @Test
+ public void create() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int baseState = 0;
+ final int currentState = 2;
+
+ final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+ assertNotNull(info.supportedStates);
+ assertEquals(supportedStates, info.supportedStates);
+ assertEquals(baseState, info.baseState);
+ assertEquals(currentState, info.currentState);
+ }
+
+ @Test
+ public void equals() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int baseState = 0;
+ final int currentState = 2;
+
+ final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+ assertTrue(info.equals(info));
+
+ final DeviceStateInfo sameInfo = new DeviceStateInfo(supportedStates, baseState,
+ currentState);
+ assertTrue(info.equals(sameInfo));
+
+ final DeviceStateInfo differentInfo = new DeviceStateInfo(new int[]{ 0, 2}, baseState,
+ currentState);
+ assertFalse(info.equals(differentInfo));
+ }
+
+ @Test
+ public void diff_sameObject() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int baseState = 0;
+ final int currentState = 2;
+
+ final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+ assertEquals(0, info.diff(info));
+ }
+
+ @Test
+ public void diff_differentSupportedStates() {
+ final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 0);
+ final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 2 }, 0, 0);
+ final int diff = info.diff(otherInfo);
+ assertTrue((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+ }
+
+ @Test
+ public void diff_differentNonOverrideState() {
+ final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 1, 0);
+ final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 2, 0);
+ final int diff = info.diff(otherInfo);
+ assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+ assertTrue((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+ }
+
+ @Test
+ public void diff_differentState() {
+ final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 1);
+ final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 0, 2);
+ final int diff = info.diff(otherInfo);
+ assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+ assertTrue((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+ }
+
+ @Test
+ public void writeToParcel() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int nonOverrideState = 0;
+ final int state = 2;
+ final DeviceStateInfo originalInfo =
+ new DeviceStateInfo(supportedStates, nonOverrideState, state);
+
+ final Parcel parcel = Parcel.obtain();
+ originalInfo.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
+
+ final DeviceStateInfo info = DeviceStateInfo.CREATOR.createFromParcel(parcel);
+ assertEquals(originalInfo, info);
+ }
+}
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index e7fdfb8..79b4d8b 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -16,11 +16,15 @@
package android.hardware.devicestate;
-import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import android.annotation.Nullable;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,6 +36,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.HashSet;
@@ -58,42 +63,75 @@
}
@Test
- public void registerListener() {
- mService.setBaseState(DEFAULT_DEVICE_STATE);
+ public void registerCallback() {
+ DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+ DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
- TestDeviceStateListener listener1 = new TestDeviceStateListener();
- TestDeviceStateListener listener2 = new TestDeviceStateListener();
-
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener1,
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1,
ConcurrentUtils.DIRECT_EXECUTOR);
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener2,
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(DEFAULT_DEVICE_STATE, listener1.getLastReportedState().intValue());
- assertEquals(DEFAULT_DEVICE_STATE, listener2.getLastReportedState().intValue());
+ // Verify initial callbacks
+ verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback1).onStateChanged(eq(mService.getMergedState()));
+ verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+ Mockito.reset(callback1);
+ Mockito.reset(callback2);
+
+ // Change the supported states and verify callback
+ mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE });
+ verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE });
+
+ Mockito.reset(callback1);
+ Mockito.reset(callback2);
+
+ // Change the base state and verify callback
mService.setBaseState(OTHER_DEVICE_STATE);
- assertEquals(OTHER_DEVICE_STATE, listener1.getLastReportedState().intValue());
- assertEquals(OTHER_DEVICE_STATE, listener2.getLastReportedState().intValue());
+ verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback1).onStateChanged(eq(mService.getMergedState()));
+ verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+ Mockito.reset(callback1);
+ Mockito.reset(callback2);
+
+ // Change the requested state and verify callback
+ DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
+ mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
+
+ verify(callback1).onStateChanged(eq(mService.getMergedState()));
+ verify(callback2).onStateChanged(eq(mService.getMergedState()));
}
@Test
- public void unregisterListener() {
- mService.setBaseState(DEFAULT_DEVICE_STATE);
+ public void unregisterCallback() {
+ DeviceStateCallback callback = mock(DeviceStateCallback.class);
- TestDeviceStateListener listener = new TestDeviceStateListener();
-
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
- mDeviceStateManagerGlobal.unregisterDeviceStateListener(listener);
+ // Verify initial callbacks
+ verify(callback).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback).onStateChanged(eq(mService.getMergedState()));
+ Mockito.reset(callback);
+ mDeviceStateManagerGlobal.unregisterDeviceStateCallback(callback);
+
+ mService.setSupportedStates(new int[]{OTHER_DEVICE_STATE});
mService.setBaseState(OTHER_DEVICE_STATE);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+ verifyZeroInteractions(callback);
}
@Test
- public void submittingRequestRegisteredCallback() {
+ public void submittingRequestRegistersCallback() {
assertTrue(mService.mCallbacks.isEmpty());
DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
@@ -104,37 +142,22 @@
@Test
public void submitRequest() {
- mService.setBaseState(DEFAULT_DEVICE_STATE);
-
- TestDeviceStateListener listener = new TestDeviceStateListener();
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+ DeviceStateCallback callback = mock(DeviceStateCallback.class);
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+ verify(callback).onStateChanged(eq(mService.getBaseState()));
+ Mockito.reset(callback);
DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
- assertEquals(OTHER_DEVICE_STATE, listener.getLastReportedState().intValue());
+ verify(callback).onStateChanged(eq(OTHER_DEVICE_STATE));
+ Mockito.reset(callback);
mDeviceStateManagerGlobal.cancelRequest(request);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
- }
-
- private final class TestDeviceStateListener implements DeviceStateManager.DeviceStateListener {
- @Nullable
- private Integer mLastReportedDeviceState;
-
- @Override
- public void onDeviceStateChanged(int deviceState) {
- mLastReportedDeviceState = deviceState;
- }
-
- @Nullable
- public Integer getLastReportedState() {
- return mLastReportedDeviceState;
- }
+ verify(callback).onStateChanged(eq(mService.getBaseState()));
}
private static final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
@@ -150,12 +173,34 @@
}
}
+ private int[] mSupportedStates = new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
private int mBaseState = DEFAULT_DEVICE_STATE;
- private int mMergedState = DEFAULT_DEVICE_STATE;
private ArrayList<Request> mRequests = new ArrayList<>();
private Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
+ private DeviceStateInfo getInfo() {
+ final int mergedState = mRequests.isEmpty()
+ ? mBaseState : mRequests.get(mRequests.size() - 1).state;
+ return new DeviceStateInfo(mSupportedStates, mBaseState, mergedState);
+ }
+
+ private void notifyDeviceStateInfoChanged() {
+ final DeviceStateInfo info = getInfo();
+ for (IDeviceStateManagerCallback callback : mCallbacks) {
+ try {
+ callback.onDeviceStateInfoChanged(info);
+ } catch (RemoteException e) {
+ // Do nothing. Should never happen.
+ }
+ }
+ }
+
+ @Override
+ public DeviceStateInfo getDeviceStateInfo() {
+ return getInfo();
+ }
+
@Override
public void registerCallback(IDeviceStateManagerCallback callback) {
if (mCallbacks.contains(callback)) {
@@ -163,16 +208,6 @@
}
mCallbacks.add(callback);
- try {
- callback.onDeviceStateChanged(mMergedState);
- } catch (RemoteException e) {
- // Do nothing. Should never happen.
- }
- }
-
- @Override
- public int[] getSupportedDeviceStates() {
- return new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
}
@Override
@@ -190,7 +225,7 @@
final Request request = new Request(token, state, flags);
mRequests.add(request);
- notifyStateChangedIfNeeded();
+ notifyDeviceStateInfoChanged();
for (IDeviceStateManagerCallback callback : mCallbacks) {
try {
@@ -223,32 +258,29 @@
// Do nothing. Should never happen.
}
}
- notifyStateChangedIfNeeded();
+ notifyDeviceStateInfoChanged();
+ }
+
+ public void setSupportedStates(int[] states) {
+ mSupportedStates = states;
+ notifyDeviceStateInfoChanged();
+ }
+
+ public int[] getSupportedStates() {
+ return mSupportedStates;
}
public void setBaseState(int state) {
mBaseState = state;
- notifyStateChangedIfNeeded();
+ notifyDeviceStateInfoChanged();
}
- private void notifyStateChangedIfNeeded() {
- final int originalMergedState = mMergedState;
+ public int getBaseState() {
+ return mBaseState;
+ }
- if (!mRequests.isEmpty()) {
- mMergedState = mRequests.get(mRequests.size() - 1).state;
- } else {
- mMergedState = mBaseState;
- }
-
- if (mMergedState != originalMergedState) {
- for (IDeviceStateManagerCallback callback : mCallbacks) {
- try {
- callback.onDeviceStateChanged(mMergedState);
- } catch (RemoteException e) {
- // Do nothing. Should never happen.
- }
- }
- }
+ public int getMergedState() {
+ return getInfo().currentState;
}
}
}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index d2b20b4..0808186 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -298,7 +298,7 @@
null /* pendingResults */, null /* pendingNewIntents */,
null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
mThread /* client */, null /* asssitToken */,
- null /* fixedRotationAdjustments */);
+ null /* fixedRotationAdjustments */, null /* shareableActivityToken */);
}
@Override
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index f6d7685..2f41b90 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -173,3 +173,10 @@
src: "com.android.car.shell.xml",
filename_from_src: true,
}
+
+prebuilt_etc {
+ name: "allowed_privapp_com.android.car.activityresolver",
+ sub_dir: "permissions",
+ src: "com.android.car.activityresolver.xml",
+ filename_from_src: true,
+}
diff --git a/data/etc/car/android.car.cluster.xml b/data/etc/car/android.car.cluster.xml
index d7f29da..de3acca 100644
--- a/data/etc/car/android.car.cluster.xml
+++ b/data/etc/car/android.car.cluster.xml
@@ -20,5 +20,7 @@
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="android.car.permission.CAR_ENGINE_DETAILED"/>
+ <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
</privapp-permissions>
</permissions>
diff --git a/packages/SystemUI/res/layout/qs_tile_label_divider.xml b/data/etc/car/com.android.car.activityresolver.xml
similarity index 71%
rename from packages/SystemUI/res/layout/qs_tile_label_divider.xml
rename to data/etc/car/com.android.car.activityresolver.xml
index 150a5b8..d48bc15 100644
--- a/packages/SystemUI/res/layout/qs_tile_label_divider.xml
+++ b/data/etc/car/com.android.car.activityresolver.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2020 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,5 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<View />
\ No newline at end of file
+<permissions>
+ <privapp-permissions package="com.android.car.activityresolver">
+ <permission name="android.permission.MANAGE_USERS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/car/com.android.car.bugreport.xml b/data/etc/car/com.android.car.bugreport.xml
index c3642d88..2ff9835 100644
--- a/data/etc/car/com.android.car.bugreport.xml
+++ b/data/etc/car/com.android.car.bugreport.xml
@@ -21,5 +21,6 @@
<permission name="android.permission.READ_LOGS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
+ <permission name="android.car.permission.CAR_DRIVING_STATE"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml
index 0e49284..ac16af3 100644
--- a/data/etc/car/com.android.car.carlauncher.xml
+++ b/data/etc/car/com.android.car.carlauncher.xml
@@ -17,9 +17,10 @@
<permissions>
<privapp-permissions package="com.android.car.carlauncher">
<permission name="android.permission.ACTIVITY_EMBEDDING"/>
- <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+ <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
<permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/car/com.android.car.dialer.xml b/data/etc/car/com.android.car.dialer.xml
index d44f5a1..61ae53a 100644
--- a/data/etc/car/com.android.car.dialer.xml
+++ b/data/etc/car/com.android.car.dialer.xml
@@ -18,5 +18,6 @@
<privapp-permissions package="com.android.car.dialer">
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/car/com.android.car.hvac.xml b/data/etc/car/com.android.car.hvac.xml
index d3631e0..534d44d 100644
--- a/data/etc/car/com.android.car.hvac.xml
+++ b/data/etc/car/com.android.car.hvac.xml
@@ -17,5 +17,6 @@
<permissions>
<privapp-permissions package="com.android.car.hvac">
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/car/com.android.car.radio.xml b/data/etc/car/com.android.car.radio.xml
index d7853ab..ed8652c 100644
--- a/data/etc/car/com.android.car.radio.xml
+++ b/data/etc/car/com.android.car.radio.xml
@@ -18,5 +18,7 @@
<privapp-permissions package="com.android.car.radio">
<permission name="android.permission.ACCESS_BROADCAST_RADIO"/>
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+ <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+ <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index bd30d7a..e6196c2 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -51,5 +51,41 @@
<!-- use for rotary fragment to enable/disable packages related to rotary -->
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+
+ <!-- CarService permissions -->
+ <!-- TODO: Explain why so many permissions are required -->
+ <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
+ <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+ <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
+ <permission name="android.car.permission.CAR_DIAGNOSTICS"/>
+ <permission name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
+ <permission name="android.car.permission.CAR_DRIVING_STATE"/>
+ <permission name="android.car.permission.CAR_DYNAMICS_STATE"/>
+ <permission name="android.car.permission.CAR_EXTERIOR_LIGHTS"/>
+ <permission name="android.car.permission.CAR_IDENTIFICATION"/>
+ <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+ <permission name="android.car.permission.CAR_MILEAGE"/>
+ <permission name="android.car.permission.CAR_MOCK_VEHICLE_HAL"/>
+ <permission name="android.car.permission.CAR_NAVIGATION_MANAGER"/>
+ <permission name="android.car.permission.CAR_POWER"/>
+ <permission name="android.car.permission.CAR_PROJECTION"/>
+ <permission name="android.car.permission.CAR_TIRES"/>
+ <permission name="android.car.permission.CAR_TEST_SERVICE"/>
+ <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"/>
+ <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/>
+ <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
+ <permission name="android.car.permission.CONTROL_CAR_DOORS"/>
+ <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/>
+ <permission name="android.car.permission.CONTROL_CAR_FEATURES"/>
+ <permission name="android.car.permission.CONTROL_CAR_MIRRORS"/>
+ <permission name="android.car.permission.CONTROL_CAR_SEATS"/>
+ <permission name="android.car.permission.CONTROL_CAR_WINDOWS"/>
+ <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"/>
+ <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"/>
+ <permission name="android.car.permission.READ_CAR_STEERING"/>
+ <permission name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"/>
+ <permission name="android.car.permission.STORAGE_MONITORING"/>
+ <permission name="android.car.permission.VMS_PUBLISHER"/>
+ <permission name="android.car.permission.VMS_SUBSCRIBER"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8fd5d80..48b297d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -68,6 +68,11 @@
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.imsserviceentitlement">
+ <permission name="android.permission.MODIFY_PHONE_STATE" />
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+ </privapp-permissions>
+
<privapp-permissions package="com.android.launcher3">
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
</privapp-permissions>
@@ -406,8 +411,6 @@
<permission name="android.permission.SET_WALLPAPER" />
<permission name="android.permission.SET_WALLPAPER_COMPONENT" />
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
- <!-- Permissions required for Incremental CTS tests -->
- <permission name="com.android.permission.USE_INSTALLER_V2"/>
<permission name="android.permission.LOADER_USAGE_STATS"/>
<!-- Permission required to test system only camera devices. -->
<permission name="android.permission.SYSTEM_CAMERA" />
@@ -480,6 +483,8 @@
<permission name="android.permission.SIGNAL_REBOOT_READINESS" />
<!-- Permission required for CTS test - PeopleManagerTest -->
<permission name="android.permission.READ_PEOPLE_DATA" />
+ <!-- Permission required for CTS test - UiTranslationManagerTest -->
+ <permission name="android.permission.MANAGE_UI_TRANSLATION" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 4f188cc..66b8eae 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -245,7 +245,7 @@
<alias name="monaco" to="monospace" />
<family name="serif-monospace">
- <font weight="400" style="normal">CutiveMono.ttf</font>
+ <font weight="400" style="normal">CutiveMono-Regular.ttf</font>
</family>
<alias name="courier" to="serif-monospace" />
<alias name="courier new" to="serif-monospace" />
@@ -255,7 +255,7 @@
</family>
<family name="cursive">
- <font weight="400" style="normal">DancingScript-Regular.ttf</font>
+ <font weight="400" style="normal">DancingScript.ttf</font>
<font weight="700" style="normal">DancingScript-Bold.ttf</font>
</family>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index f1f9a5f..e222570 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -153,6 +153,13 @@
* resource bitmaps often are) the filtering will already have been
* done.</p>
*
+ * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
+ * accelerated drawing always uses bilinear sampling on scaled bitmaps,
+ * regardless of this flag. On devices running {@link Build.VERSION_CODES#Q}
+ * and above, this flag defaults to being set on a new {@code Paint}. It can
+ * be cleared with {@link #setFlags} or {@link #setFilterBitmap}.</p>
+ *
+ * @see #Paint()
* @see #Paint(int)
* @see #setFlags(int)
*/
@@ -558,6 +565,12 @@
/**
* Create a new paint with default settings.
+ *
+ * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
+ * accelerated drawing always acts as if {@link #FILTER_BITMAP_FLAG} is set.
+ * On devices running {@link Build.VERSION_CODES#Q} and above,
+ * {@code FILTER_BITMAP_FLAG} is set by this constructor, and it can be
+ * cleared with {@link #setFlags} or {@link #setFilterBitmap}.</p>
*/
public Paint() {
this(0);
@@ -567,6 +580,13 @@
* Create a new paint with the specified flags. Use setFlags() to change
* these after the paint is created.
*
+ * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
+ * accelerated drawing always acts as if {@link #FILTER_BITMAP_FLAG} is set.
+ * On devices running {@link Build.VERSION_CODES#Q} and above,
+ * {@code FILTER_BITMAP_FLAG} is always set by this constructor, regardless
+ * of the value of {@code flags}. It can be cleared with {@link #setFlags} or
+ * {@link #setFilterBitmap}.</p>
+ *
* @param flags initial flag bits, as if they were passed via setFlags().
*/
public Paint(int flags) {
@@ -991,6 +1011,7 @@
* device pixels. That is dependent on dithering and xfermodes.
*
* @see #setFilterBitmap(boolean) setFilterBitmap()
+ * @see #FILTER_BITMAP_FLAG
*/
public final boolean isFilterBitmap() {
return (getFlags() & FILTER_BITMAP_FLAG) != 0;
@@ -1004,6 +1025,7 @@
*
* @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
* flags, false to clear it.
+ * @see #FILTER_BITMAP_FLAG
*/
public void setFilterBitmap(boolean filter) {
nSetFilterBitmap(mNativePaint, filter);
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 32c777c..c807882 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -172,9 +172,9 @@
* @hide
*/
@UnsupportedAppUsage
- public long native_instance;
+ public final long native_instance;
- private Runnable mCleaner;
+ private final Runnable mCleaner;
/** @hide */
@IntDef(value = {NORMAL, BOLD, ITALIC, BOLD_ITALIC})
@@ -189,9 +189,9 @@
/** @hide */ public static final int STYLE_MASK = 0x03;
@UnsupportedAppUsage
- private @Style int mStyle = 0;
+ private @Style final int mStyle;
- private @IntRange(from = 0, to = FontStyle.FONT_WEIGHT_MAX) int mWeight = 0;
+ private @IntRange(from = 0, to = FontStyle.FONT_WEIGHT_MAX) final int mWeight;
// Value for weight and italic. Indicates the value is resolved by font metadata.
// Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
@@ -207,6 +207,7 @@
private static final int STYLE_NORMAL = 0;
private static final int STYLE_ITALIC = 1;
+ @GuardedBy("this")
private int[] mSupportedAxes;
private static final int[] EMPTY_AXES = {};
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index c81c8c54..ed789f0 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -21,6 +21,7 @@
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.security.usermanager.IKeystoreUserManager;
+import android.system.keystore2.Domain;
import android.system.keystore2.ResponseCode;
import android.util.Log;
@@ -39,7 +40,7 @@
}
/**
- * Informs keystore2 about adding a user
+ * Informs Keystore 2.0 about adding a user
*
* @param userId - Android user id of the user being added
* @return 0 if successful or a {@code ResponseCode}
@@ -60,7 +61,7 @@
}
/**
- * Informs keystore2 about removing a usergit mer
+ * Informs Keystore 2.0 about removing a usergit mer
*
* @param userId - Android user id of the user being removed
* @return 0 if successful or a {@code ResponseCode}
@@ -81,7 +82,7 @@
}
/**
- * Informs keystore2 about changing user's password
+ * Informs Keystore 2.0 about changing user's password
*
* @param userId - Android user id of the user
* @param password - a secret derived from the synthetic password provided by the
@@ -102,4 +103,22 @@
return SYSTEM_ERROR;
}
}
+
+ /**
+ * Informs Keystore 2.0 that an app was uninstalled and the corresponding namspace is to
+ * be cleared.
+ */
+ public static int clearNamespace(@Domain int domain, long namespace) {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+ try {
+ getService().clearNamespace(domain, namespace);
+ return 0;
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "clearNamespace failed", e);
+ return e.errorCode;
+ } catch (Exception e) {
+ Log.e(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ }
+ }
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 198df40..93658e6 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -43,6 +43,7 @@
import android.security.keystore.KeyProperties;
import android.security.keystore.KeystoreResponse;
import android.security.keystore.UserNotAuthenticatedException;
+import android.system.keystore2.Domain;
import android.util.Log;
import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
@@ -466,6 +467,9 @@
public boolean clearUid(int uid) {
try {
+ if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
+ return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
+ }
return mBinder.clear_uid(uid) == NO_ERROR;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 476e4d7..6ac3821 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -24,6 +24,7 @@
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.security.keymaster.KeymasterDefs;
+import android.system.keystore2.Domain;
import android.system.keystore2.IKeystoreService;
import android.system.keystore2.KeyDescriptor;
import android.system.keystore2.KeyEntryResponse;
@@ -157,6 +158,50 @@
}
/**
+ * Grant string prefix as used by the keystore boringssl engine. Must be kept in sync
+ * with system/security/keystore-engine. Note: The prefix here includes the 0x which
+ * std::stringstream used in keystore-engine needs to identify the number as hex represented.
+ * Here we include it in the prefix, because Long#parseUnsignedLong does not understand it
+ * and gets the radix as explicit argument.
+ * @hide
+ */
+ private static final String KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX =
+ "ks2_keystore-engine_grant_id:0x";
+
+ /**
+ * This function turns a grant identifier into a specific string that is understood by the
+ * keystore-engine in system/security/keystore-engine. Is only used by VPN and WI-FI components
+ * to allow certain system components like racoon or vendor components like WPA supplicant
+ * to use keystore keys with boring ssl.
+ *
+ * @param grantId the grant id as returned by {@link #grant} in the {@code nspace} filed of
+ * the resulting {@code KeyDescriptor}.
+ * @return The grant descriptor string.
+ * @hide
+ */
+ public static String makeKeystoreEngineGrantString(long grantId) {
+ return String.format("%s%016X", KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX, grantId);
+ }
+
+ /**
+ * Convenience function to turn a keystore engine grant string as returned by
+ * {@link #makeKeystoreEngineGrantString(long)} back into a grant KeyDescriptor.
+ *
+ * @param grantString As string returned by {@link #makeKeystoreEngineGrantString(long)}
+ * @return The grant key descriptor.
+ * @hide
+ */
+ public static KeyDescriptor keystoreEngineGrantString2KeyDescriptor(String grantString) {
+ KeyDescriptor key = new KeyDescriptor();
+ key.domain = Domain.GRANT;
+ key.nspace = Long.parseUnsignedLong(
+ grantString.substring(KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX.length()), 16);
+ key.alias = null;
+ key.blob = null;
+ return key;
+ }
+
+ /**
* Create a grant that allows the grantee identified by {@code granteeUid} to use
* the key specified by {@code descriptor} withint the restrictions given by
* {@code accessVectore}.
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 35059ac..d36695b 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -43,6 +43,7 @@
import javax.crypto.Cipher;
import javax.crypto.Mac;
+import javax.crypto.SecretKey;
/**
* A provider focused on providing JCA interfaces for the Android KeyStore.
@@ -299,13 +300,26 @@
}
}
+ /** @hide **/
+ @NonNull
+ public static SecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
+ @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor)
+ throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
+
+ AndroidKeyStoreKey key =
+ loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor);
+ if (key instanceof SecretKey) {
+ return (SecretKey) key;
+ } else {
+ throw new UnrecoverableKeyException("No secret key found by the given alias.");
+ }
+ }
@NonNull
private static AndroidKeyStoreSecretKey makeAndroidKeyStoreSecretKeyFromKeyEntryResponse(
@NonNull KeyDescriptor descriptor,
@NonNull KeyEntryResponse response, int algorithm, int digest)
throws UnrecoverableKeyException {
-
@KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
try {
keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
@@ -337,7 +351,6 @@
public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
@NonNull KeyStore2 keyStore, @NonNull String alias, int namespace)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-
KeyDescriptor descriptor = new KeyDescriptor();
if (namespace == KeyProperties.NAMESPACE_APPLICATION) {
descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 7376d98..cc353dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -25,6 +25,7 @@
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -44,6 +45,7 @@
private final FullscreenTaskListener mFullscreenTaskListener;
private final ShellExecutor mMainExecutor;
private final Transitions mTransitions;
+ private final Optional<StartingSurface> mStartingSurfaceOptional;
private final InitImpl mImpl = new InitImpl();
@@ -53,6 +55,7 @@
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
+ Optional<StartingSurface> startingSurfaceOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
ShellExecutor mainExecutor) {
@@ -62,6 +65,7 @@
legacySplitScreenOptional,
splitScreenOptional,
appPairsOptional,
+ startingSurfaceOptional,
fullscreenTaskListener,
transitions,
mainExecutor).mImpl;
@@ -73,6 +77,7 @@
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
+ Optional<StartingSurface> startingSurfaceOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
ShellExecutor mainExecutor) {
@@ -85,6 +90,7 @@
mFullscreenTaskListener = fullscreenTaskListener;
mTransitions = transitions;
mMainExecutor = mainExecutor;
+ mStartingSurfaceOptional = startingSurfaceOptional;
}
private void init() {
@@ -93,6 +99,7 @@
mShellTaskOrganizer.addListenerForType(
mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
+ mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
// Register the shell organizer
mShellTaskOrganizer.registerOrganizer();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index efc55c4..9ddeb2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -44,7 +44,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
+import com.android.wm.shell.startingsurface.StartingSurface;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -110,7 +110,7 @@
private final ArrayMap<IBinder, TaskListener> mLaunchCookieToListener = new ArrayMap<>();
private final Object mLock = new Object();
- private final StartingSurfaceDrawer mStartingSurfaceDrawer;
+ private StartingSurface mStartingSurface;
/**
* In charge of showing size compat UI. Can be {@code null} if device doesn't support size
@@ -120,23 +120,19 @@
private final SizeCompatUIController mSizeCompatUI;
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
- this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */,
- new StartingSurfaceDrawer(context, mainExecutor));
+ this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */);
}
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
SizeCompatUIController sizeCompatUI) {
- this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
- new StartingSurfaceDrawer(context, mainExecutor));
+ this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI);
}
@VisibleForTesting
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
- Context context, @Nullable SizeCompatUIController sizeCompatUI,
- StartingSurfaceDrawer startingSurfaceDrawer) {
+ Context context, @Nullable SizeCompatUIController sizeCompatUI) {
super(taskOrganizerController, mainExecutor);
mSizeCompatUI = sizeCompatUI;
- mStartingSurfaceDrawer = startingSurfaceDrawer;
}
@Override
@@ -163,6 +159,15 @@
}
/**
+ * @hide
+ */
+ public void initStartingSurface(StartingSurface startingSurface) {
+ synchronized (mLock) {
+ mStartingSurface = startingSurface;
+ }
+ }
+
+ /**
* Adds a listener for a specific task id.
*/
public void addListenerForTaskId(TaskListener listener, int taskId) {
@@ -254,17 +259,23 @@
@Override
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
- mStartingSurfaceDrawer.addStartingWindow(info, appToken);
+ if (mStartingSurface != null) {
+ mStartingSurface.addStartingWindow(info, appToken);
+ }
}
@Override
public void removeStartingWindow(int taskId) {
- mStartingSurfaceDrawer.removeStartingWindow(taskId);
+ if (mStartingSurface != null) {
+ mStartingSurface.removeStartingWindow(taskId);
+ }
}
@Override
public void copySplashScreenView(int taskId) {
- mStartingSurfaceDrawer.copySplashScreenView(taskId);
+ if (mStartingSurface != null) {
+ mStartingSurface.copySplashScreenView(taskId);
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 5992447..46884fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -157,6 +157,7 @@
});
options.setLaunchCookie(launchCookie);
options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ options.setRemoveWithTaskOrganizer(true);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index 19c3cf9..57a2b6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -227,24 +227,30 @@
/*
* Fade animation for consecutive flyouts.
*/
- void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, float stackY) {
+ void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos,
+ boolean hideDot) {
final Runnable afterFadeOut = () -> {
updateFlyoutMessage(flyoutMessage, parentWidth);
// Wait for TextViews to layout with updated height.
post(() -> {
- mFlyoutY = stackY + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
- fade(true /* in */, () -> {} /* after */);
+ fade(true /* in */, stackPos, hideDot, () -> {} /* after */);
} /* after */ );
};
- fade(false /* in */, afterFadeOut);
+ fade(false /* in */, stackPos, hideDot, afterFadeOut);
}
/*
* Fade-out above or fade-in from below.
*/
- private void fade(boolean in, Runnable afterFade) {
+ private void fade(boolean in, PointF stackPos, boolean hideDot, Runnable afterFade) {
+ mFlyoutY = stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
+
setAlpha(in ? 0f : 1f);
setTranslationY(in ? mFlyoutY + FLYOUT_FADE_Y : mFlyoutY);
+ updateFlyoutX(stackPos.x);
+ setTranslationX(mRestingTranslationX);
+ updateDot(stackPos, hideDot);
+
animate()
.alpha(in ? 1f : 0f)
.setDuration(in ? FLYOUT_FADE_IN_DURATION : FLYOUT_FADE_OUT_DURATION)
@@ -287,6 +293,33 @@
mMessageText.setText(flyoutMessage.message);
}
+ void updateFlyoutX(float stackX) {
+ // Calculate the translation required to position the flyout next to the bubble stack,
+ // with the desired padding.
+ mRestingTranslationX = mArrowPointingLeft
+ ? stackX + mBubbleSize + mFlyoutSpaceFromBubble
+ : stackX - getWidth() - mFlyoutSpaceFromBubble;
+ }
+
+ void updateDot(PointF stackPos, boolean hideDot) {
+ // Calculate the difference in size between the flyout and the 'dot' so that we can
+ // transform into the dot later.
+ final float newDotSize = hideDot ? 0f : mNewDotSize;
+ mFlyoutToDotWidthDelta = getWidth() - newDotSize;
+ mFlyoutToDotHeightDelta = getHeight() - newDotSize;
+
+ // Calculate the translation values needed to be in the correct 'new dot' position.
+ final float adjustmentForScaleAway = hideDot ? 0f : (mOriginalDotSize / 2f);
+ final float dotPositionX = stackPos.x + mDotCenter[0] - adjustmentForScaleAway;
+ final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
+
+ final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
+ final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
+
+ mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
+ mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
+ }
+
/** Configures the flyout, collapsed into dot form. */
void setupFlyoutStartingAsDot(
Bubble.FlyoutMessage flyoutMessage,
@@ -322,29 +355,8 @@
mFlyoutY =
stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
setTranslationY(mFlyoutY);
-
- // Calculate the translation required to position the flyout next to the bubble stack,
- // with the desired padding.
- mRestingTranslationX = mArrowPointingLeft
- ? stackPos.x + mBubbleSize + mFlyoutSpaceFromBubble
- : stackPos.x - getWidth() - mFlyoutSpaceFromBubble;
-
- // Calculate the difference in size between the flyout and the 'dot' so that we can
- // transform into the dot later.
- final float newDotSize = hideDot ? 0f : mNewDotSize;
- mFlyoutToDotWidthDelta = getWidth() - newDotSize;
- mFlyoutToDotHeightDelta = getHeight() - newDotSize;
-
- // Calculate the translation values needed to be in the correct 'new dot' position.
- final float adjustmentForScaleAway = hideDot ? 0f : (mOriginalDotSize / 2f);
- final float dotPositionX = stackPos.x + mDotCenter[0] - adjustmentForScaleAway;
- final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
-
- final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
- final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
-
- mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
- mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
+ updateFlyoutX(stackPos.x);
+ updateDot(stackPos, hideDot);
if (onLayoutComplete != null) {
onLayoutComplete.run();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index a8ab406..78820a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -2431,7 +2431,7 @@
if (mFlyout.getVisibility() == View.VISIBLE) {
mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
- mStackAnimationController.getStackPosition().y);
+ mStackAnimationController.getStackPosition(), !bubble.showDot());
} else {
mFlyout.setVisibility(INVISIBLE);
mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 4564af4..f118b1e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -50,6 +50,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Contains information about the layout-properties of a display. This refers to internal layout
@@ -82,6 +83,31 @@
private boolean mHasStatusBar = false;
private int mNavBarFrameHeight = 0;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DisplayLayout)) return false;
+ final DisplayLayout other = (DisplayLayout) o;
+ return mUiMode == other.mUiMode
+ && mWidth == other.mWidth
+ && mHeight == other.mHeight
+ && Objects.equals(mCutout, other.mCutout)
+ && mRotation == other.mRotation
+ && mDensityDpi == other.mDensityDpi
+ && Objects.equals(mNonDecorInsets, other.mNonDecorInsets)
+ && Objects.equals(mStableInsets, other.mStableInsets)
+ && mHasNavigationBar == other.mHasNavigationBar
+ && mHasStatusBar == other.mHasStatusBar
+ && mNavBarFrameHeight == other.mNavBarFrameHeight;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
+ mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
+ mNavBarFrameHeight);
+ }
+
/**
* Create empty layout.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index fb70cbe5..4bb8e9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -39,12 +39,12 @@
import android.view.IWindowSessionCallback;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.ScrollCaptureResponse;
import android.view.SurfaceControl;
-import android.view.SurfaceSession;
import android.view.SurfaceControlViewHost;
+import android.view.SurfaceSession;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
import android.window.ClientWindowFrames;
@@ -371,7 +371,11 @@
@Override
public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
try {
- callbacks.onUnavailable();
+ callbacks.onScrollCaptureResponse(
+ new ScrollCaptureResponse.Builder()
+ .setDescription("Not Implemented")
+ .build());
+
} catch (RemoteException ex) {
// ignore
}
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 66560d3..a52db24 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
@@ -90,15 +90,15 @@
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private PipTransitionAnimator mCurrentAnimator;
-
- private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+ private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
ThreadLocal.withInitial(() -> {
AnimationHandler handler = new AnimationHandler();
handler.setProvider(new SfVsyncFrameCallbackProvider());
return handler;
});
+ private PipTransitionAnimator mCurrentAnimator;
+
public PipAnimationController(PipSurfaceTransactionHelper helper) {
mSurfaceTransactionHelper = helper;
}
@@ -268,6 +268,7 @@
if (mPipAnimationCallback != null) {
mPipAnimationCallback.onPipAnimationEnd(mTaskInfo, tx, this);
}
+ mTransitionDirection = TRANSITION_DIRECTION_NONE;
}
@Override
@@ -275,6 +276,7 @@
if (mPipAnimationCallback != null) {
mPipAnimationCallback.onPipAnimationCancel(mTaskInfo, this);
}
+ mTransitionDirection = TRANSITION_DIRECTION_NONE;
}
@Override public void onAnimationRepeat(Animator animation) {}
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 7fff37d..9a584c6 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
@@ -65,6 +65,7 @@
import com.android.wm.shell.pip.PipUtils;
import java.io.PrintWriter;
+import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -101,9 +102,12 @@
*/
private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
- if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
- // Skip if 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.
+ if (!mPipTaskOrganizer.isInPip()
+ || mPipBoundsState.getDisplayLayout().rotation() == toRotation
+ || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
+ // 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.
onDisplayRotationChangedNotInPip(mContext, toRotation);
// do not forget to update the movement bounds as well.
updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
@@ -378,6 +382,9 @@
}
private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) {
+ if (Objects.equals(layout, mPipBoundsState.getDisplayLayout())) {
+ return;
+ }
Runnable updateDisplayLayout = () -> {
mPipBoundsState.setDisplayLayout(layout);
updateMovementBounds(null /* toBounds */,
@@ -476,8 +483,11 @@
int launcherRotation, int shelfHeight) {
setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
onDisplayRotationChangedNotInPip(mContext, launcherRotation);
- return mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
+ final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
pictureInPictureParams);
+ // sync mPipBoundsState with the newly calculated bounds.
+ mPipBoundsState.setNormalBounds(entryBounds);
+ return entryBounds;
}
private void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 22c9751..bbfbc40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -362,8 +362,9 @@
@Override
public void onSnappedToDismiss(boolean bottomOrRight) {
- final boolean mainStageToTop = bottomOrRight
- && mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
+ final boolean mainStageToTop =
+ bottomOrRight ? mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT
+ : mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT;
exitSplitScreen(mainStageToTop ? mMainStage : mSideStage);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
new file mode 100644
index 0000000..2c4ceff
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.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 com.android.wm.shell.startingsurface;
+
+import android.os.IBinder;
+import android.window.StartingWindowInfo;
+
+/**
+ * Interface to engage starting window feature.
+ */
+public interface StartingSurface {
+ /**
+ * Called when a task need a starting window.
+ */
+ void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken);
+ /**
+ * Called when the content of a task is ready to show, starting window can be removed.
+ */
+ void removeStartingWindow(int taskId);
+ /**
+ * Called when the Task wants to copy the splash screen.
+ * @param taskId
+ */
+ void copySplashScreenView(int taskId);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 5332291..8144071 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -16,15 +16,9 @@
package com.android.wm.shell.startingsurface;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.res.Configuration.EMPTY;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
@@ -37,7 +31,6 @@
import android.content.res.TypedArray;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
-import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -46,7 +39,6 @@
import android.window.SplashScreenView;
import android.window.SplashScreenView.SplashScreenViewParcelable;
import android.window.StartingWindowInfo;
-import android.window.TaskOrganizer;
import android.window.TaskSnapshot;
import com.android.internal.R;
@@ -56,19 +48,13 @@
import java.util.function.Consumer;
/**
- * Implementation to draw the starting window to an application, and remove the starting window
- * until the application displays its own window.
- *
- * When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
- * starting window and attached to the Task, then when the Task want to remove the starting window,
- * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
- * class to remove the starting window of the Task.
+ * A class which able to draw splash screen or snapshot as the starting window for a task.
* @hide
*/
public class StartingSurfaceDrawer {
static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
- static final boolean DEBUG_SPLASH_SCREEN = false;
- static final boolean DEBUG_TASK_SNAPSHOT = false;
+ static final boolean DEBUG_SPLASH_SCREEN = StartingWindowController.DEBUG_SPLASH_SCREEN;
+ static final boolean DEBUG_TASK_SNAPSHOT = StartingWindowController.DEBUG_TASK_SNAPSHOT;
private final Context mContext;
private final DisplayManager mDisplayManager;
@@ -107,106 +93,10 @@
return context.createDisplayContext(targetDisplay);
}
- private static class PreferredStartingTypeHelper {
- private static final int STARTING_TYPE_NO = 0;
- private static final int STARTING_TYPE_SPLASH_SCREEN = 1;
- private static final int STARTING_TYPE_SNAPSHOT = 2;
-
- TaskSnapshot mSnapshot;
- int mPreferredType;
-
- PreferredStartingTypeHelper(StartingWindowInfo taskInfo) {
- final int parameter = taskInfo.startingWindowTypeParameter;
- final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
- final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
- final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
- final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
- final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
- mPreferredType = preferredStartingWindowType(taskInfo, newTask, taskSwitch,
- processRunning, allowTaskSnapshot, activityCreated);
- }
-
- // reference from ActivityRecord#getStartingWindowType
- private int preferredStartingWindowType(StartingWindowInfo windowInfo,
- boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated) {
- if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
- + " taskSwitch " + taskSwitch
- + " processRunning " + processRunning
- + " allowTaskSnapshot " + allowTaskSnapshot
- + " activityCreated " + activityCreated);
- }
-
- if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
- return STARTING_TYPE_SPLASH_SCREEN;
- } else if (taskSwitch && allowTaskSnapshot) {
- final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
- if (isSnapshotCompatible(windowInfo, snapshot)) {
- return STARTING_TYPE_SNAPSHOT;
- }
- if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
- return STARTING_TYPE_SPLASH_SCREEN;
- }
- return STARTING_TYPE_NO;
- } else {
- return STARTING_TYPE_NO;
- }
- }
-
- /**
- * Returns {@code true} if the task snapshot is compatible with this activity (at least the
- * rotation must be the same).
- */
- private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
- if (snapshot == null) {
- if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
- }
- return false;
- }
-
- final int taskRotation = windowInfo.taskInfo.configuration
- .windowConfiguration.getRotation();
- final int snapshotRotation = snapshot.getRotation();
- if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
- + " snapshot " + snapshotRotation);
- }
- return taskRotation == snapshotRotation;
- }
-
- private TaskSnapshot getTaskSnapshot(int taskId) {
- if (mSnapshot != null) {
- return mSnapshot;
- }
- try {
- mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
- false/* isLowResolution */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
- return null;
- }
- return mSnapshot;
- }
- }
-
/**
- * Called when a task need a starting window.
+ * Called when a task need a splash screen starting window.
*/
- public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
- final PreferredStartingTypeHelper helper =
- new PreferredStartingTypeHelper(windowInfo);
- if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) {
- addSplashScreenStartingWindow(windowInfo, appToken);
- } else if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SNAPSHOT) {
- final TaskSnapshot snapshot = helper.mSnapshot;
- makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
- }
- // If prefer don't show, then don't show!
- }
-
- private void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ public void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
final RunningTaskInfo taskInfo = windowInfo.taskInfo;
final ActivityInfo activityInfo = taskInfo.topActivityInfo;
if (activityInfo == null) {
@@ -378,8 +268,8 @@
/**
* Called when a task need a snapshot starting window.
*/
- private void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo,
- IBinder appToken, TaskSnapshot snapshot) {
+ void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo, IBinder appToken,
+ TaskSnapshot snapshot) {
final int taskId = startingWindowInfo.taskInfo.taskId;
final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
new file mode 100644
index 0000000..73bf8ac
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.window.StartingWindowInfo;
+import android.window.TaskOrganizer;
+import android.window.TaskSnapshot;
+
+import com.android.wm.shell.common.ShellExecutor;
+
+/**
+ * Implementation to draw the starting window to an application, and remove the starting window
+ * until the application displays its own window.
+ *
+ * When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
+ * starting window and attached to the Task, then when the Task want to remove the starting window,
+ * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
+ * class to remove the starting window of the Task.
+ * @hide
+ */
+public class StartingWindowController {
+ private static final String TAG = StartingWindowController.class.getSimpleName();
+ static final boolean DEBUG_SPLASH_SCREEN = false;
+ static final boolean DEBUG_TASK_SNAPSHOT = false;
+
+ private final StartingSurfaceDrawer mStartingSurfaceDrawer;
+ private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker();
+ private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
+
+ public StartingWindowController(Context context, ShellExecutor mainExecutor) {
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
+ }
+
+ /**
+ * Provide the implementation for Shell Module.
+ */
+ public StartingSurface asStartingSurface() {
+ return mImpl;
+ }
+
+ private static class StartingTypeChecker {
+ TaskSnapshot mSnapshot;
+
+ StartingTypeChecker() { }
+
+ private void reset() {
+ mSnapshot = null;
+ }
+
+ private @StartingWindowInfo.StartingWindowType int
+ estimateStartingWindowType(StartingWindowInfo windowInfo) {
+ reset();
+ final int parameter = windowInfo.startingWindowTypeParameter;
+ final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
+ final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
+ final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
+ final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
+ final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+ return estimateStartingWindowType(windowInfo, newTask, taskSwitch,
+ processRunning, allowTaskSnapshot, activityCreated);
+ }
+
+ // reference from ActivityRecord#getStartingWindowType
+ private int estimateStartingWindowType(StartingWindowInfo windowInfo,
+ boolean newTask, boolean taskSwitch, boolean processRunning,
+ boolean allowTaskSnapshot, boolean activityCreated) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+ + " taskSwitch " + taskSwitch
+ + " processRunning " + processRunning
+ + " allowTaskSnapshot " + allowTaskSnapshot
+ + " activityCreated " + activityCreated);
+ }
+ if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ if (taskSwitch && allowTaskSnapshot) {
+ final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
+ if (isSnapshotCompatible(windowInfo, snapshot)) {
+ return STARTING_WINDOW_TYPE_SNAPSHOT;
+ }
+ if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
+ }
+ return STARTING_WINDOW_TYPE_NONE;
+ }
+
+ /**
+ * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+ * rotation must be the same).
+ */
+ private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
+ if (snapshot == null) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
+ }
+ return false;
+ }
+
+ final int taskRotation = windowInfo.taskInfo.configuration
+ .windowConfiguration.getRotation();
+ final int snapshotRotation = snapshot.getRotation();
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
+ + " snapshot " + snapshotRotation);
+ }
+ return taskRotation == snapshotRotation;
+ }
+
+ private TaskSnapshot getTaskSnapshot(int taskId) {
+ if (mSnapshot != null) {
+ return mSnapshot;
+ }
+ try {
+ mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
+ false/* isLowResolution */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
+ return null;
+ }
+ return mSnapshot;
+ }
+ }
+
+ /**
+ * Called when a task need a starting window.
+ */
+ void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
+ if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
+ } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
+ final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
+ mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+ }
+ // If prefer don't show, then don't show!
+ }
+
+ void copySplashScreenView(int taskId) {
+ mStartingSurfaceDrawer.copySplashScreenView(taskId);
+ }
+
+ /**
+ * Called when the content of a task is ready to show, starting window can be removed.
+ */
+ void removeStartingWindow(int taskId) {
+ mStartingSurfaceDrawer.removeStartingWindow(taskId);
+ }
+
+ private class StartingSurfaceImpl implements StartingSurface {
+
+ @Override
+ public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ StartingWindowController.this.addStartingWindow(windowInfo, appToken);
+ }
+
+ @Override
+ public void removeStartingWindow(int taskId) {
+ StartingWindowController.this.removeStartingWindow(taskId);
+ }
+
+ @Override
+ public void copySplashScreenView(int taskId) {
+ StartingWindowController.this.copySplashScreenView(taskId);
+ }
+ }
+}
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 eb53783..5f003ba 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
@@ -71,16 +71,16 @@
}
}
- @FlakyTest
+ @Presubmit
@Test
fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
- @FlakyTest
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
testSpec.config.endRotation)
- @FlakyTest
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
testSpec.config.endRotation)
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 39c9484..d479208 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
@@ -76,17 +76,8 @@
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(isRotated)
- testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
- }
-
- @FlakyTest
- @Test
- fun navBarLayerRotatesAndScales_Flaky() {
- Assume.assumeTrue(isRotated)
- testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
- }
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
+ Surface.ROTATION_0, testSpec.config.endRotation)
@Presubmit
@Test
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 41e2864..9011f1a 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
@@ -18,7 +18,6 @@
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
@@ -125,7 +124,7 @@
}
}
- @FlakyTest
+ @Presubmit
@Test
fun testAppLayerCoversFullScreen() {
testSpec.assertLayersEnd {
@@ -133,11 +132,11 @@
}
}
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
similarity index 69%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
index 06ef79a..3e33176 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
@@ -16,12 +16,9 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
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
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -35,21 +32,10 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import org.junit.FixMethodOrder
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-/**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipToHomeTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipToHomeTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = true) { configuration ->
setup {
@@ -62,30 +48,27 @@
this.setRotation(Surface.ROTATION_0)
}
}
- transitions {
- pipApp.closePipWindow(wmHelper)
- }
}
- @Postsubmit
+ @Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
@Presubmit
@Test
- fun pipWindowBecomesInvisible() {
+ open fun pipWindowBecomesInvisible() {
testSpec.assertWm {
this.showsAppWindow(PIP_WINDOW_TITLE)
.then()
@@ -95,7 +78,7 @@
@Presubmit
@Test
- fun pipLayerBecomesInvisible() {
+ open fun pipLayerBecomesInvisible() {
testSpec.assertLayers {
this.isVisible(PIP_WINDOW_TITLE)
.then()
@@ -105,22 +88,22 @@
@Presubmit
@Test
- fun statusBarLayerRotatesScales() =
+ open fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- @Postsubmit
+ @Presubmit
@Test
- fun noUncoveredRegions() =
+ open fun noUncoveredRegions() =
testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
- @Postsubmit
+ @Presubmit
@Test
- fun navBarLayerRotatesAndScales() =
+ open fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
@FlakyTest(bugId = 151179149)
@Test
- fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
+ open fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
companion object {
@Parameterized.Parameters(name = "{0}")
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
new file mode 100644
index 0000000..0408421
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+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.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest WMShellFlickerTests:PipCloseWithDismissButton`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ pipApp.closePipWindow(wmHelper)
+ }
+ }
+}
\ 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
new file mode 100644
index 0000000..afaf33a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+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 com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest WMShellFlickerTests:PipCloseWithSwipe`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ val pipRegion = wmHelper.getWindowRegion(pipApp.component).bounds
+ val pipCenterX = pipRegion.centerX()
+ val pipCenterY = pipRegion.centerY()
+ val displayCenterX = device.displayWidth / 2
+ device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 5)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
+
+ @Postsubmit
+ @Test
+ override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
+
+ @Postsubmit
+ @Test
+ override fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Postsubmit
+ @Test
+ override fun noUncoveredRegions() = super.noUncoveredRegions()
+
+ @Postsubmit
+ @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/pip/PipMovesInAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
new file mode 100644
index 0000000..4c95da2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+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 com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.google.common.truth.Truth
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest WMShellFlickerTests:PipMovesInAllApps`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipMovesInAllApps(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ private val taplInstrumentation = LauncherInstrumentation()
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition(eachRun = false) {
+ teardown {
+ eachRun {
+ taplInstrumentation.pressHome()
+ }
+ }
+ transitions {
+ taplInstrumentation.pressHome().switchToAllApps()
+ wmHelper.waitForAppTransitionIdle()
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Postsubmit
+ @Test
+ fun pipAlwaysVisible() = testSpec.assertWm { this.showsAppWindow(pipApp.windowName) }
+
+ @Postsubmit
+ @Test
+ fun pipWindowMovesUp() = testSpec.assertWmEnd {
+ val initialState = this.trace?.first()?.wmState
+ ?: error("Trace should not be empty")
+ val startPos = initialState.pinnedWindows.first().frame
+ val currPos = this.wmState.pinnedWindows.first().frame
+ val subject = Truth.assertWithMessage("Pip should have moved up")
+ subject.that(currPos.top).isGreaterThan(startPos.top)
+ subject.that(currPos.bottom).isGreaterThan(startPos.bottom)
+ subject.that(currPos.left).isEqualTo(startPos.left)
+ subject.that(currPos.right).isEqualTo(startPos.right)
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ }
+ }
+}
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 37b49c7..df835d2 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
@@ -88,11 +88,11 @@
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
testSpec.config.endRotation, allStates = false)
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
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 704fd1d..1bb1d28 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
@@ -66,7 +66,7 @@
}
}
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
@@ -107,12 +107,12 @@
}
}
- @FlakyTest
+ @Presubmit
@Test
fun noUncoveredRegions() =
testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
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 1fcc7d0..7916ce5 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
@@ -123,11 +123,11 @@
}
}
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index a0e9f43..06b492d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -53,7 +53,6 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
import org.junit.Before;
import org.junit.Test;
@@ -79,8 +78,6 @@
private Context mContext;
@Mock
private SizeCompatUIController mSizeCompatUI;
- @Mock
- private StartingSurfaceDrawer mStartingSurfaceDrawer;
ShellTaskOrganizer mOrganizer;
private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class);
@@ -116,7 +113,7 @@
.when(mTaskOrganizerController).registerTaskOrganizer(any());
} catch (RemoteException e) {}
mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
- mSizeCompatUI, mStartingSurfaceDrawer));
+ mSizeCompatUI));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index de7d6c7..b9af9ce 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -125,7 +125,7 @@
final Handler mainLoop = new Handler(Looper.getMainLooper());
final StartingWindowInfo windowInfo =
createWindowInfo(taskId, android.R.style.Theme);
- mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).postAddWindow(
eq(taskId), eq(mBinder), any(), any(), any(), any());
@@ -143,7 +143,7 @@
final Handler mainLoop = new Handler(Looper.getMainLooper());
final StartingWindowInfo windowInfo =
createWindowInfo(taskId, 0);
- mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).postAddWindow(
eq(taskId), eq(mBinder), any(), any(), any(), any());
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 389fe7e..50eea31 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -105,7 +105,6 @@
LightingInfo::updateLighting(lightGeometry, lightInfo);
renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
SkMatrix::I());
- layerUpdateQueue->clear();
// Draw visual debugging features
if (CC_UNLIKELY(Properties::showDirtyRegions ||
@@ -113,9 +112,14 @@
SkCanvas* profileCanvas = surface->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
- profileCanvas->flush();
}
+ {
+ ATRACE_NAME("flush commands");
+ surface->flushAndSubmit();
+ }
+ layerUpdateQueue->clear();
+
// Log memory statistics
if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
dumpResourceCacheUsage();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 6456e36..1f73ac9 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -454,9 +454,6 @@
renderOverdraw(clip, nodes, contentDrawBounds, surface, preTransform);
}
- ATRACE_NAME("flush commands");
- surface->flushAndSubmit();
-
Properties::skpCaptureEnabled = previousSkpEnabled;
}
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index ad6363b..1bd943f 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -17,14 +17,15 @@
#include "SkiaVulkanPipeline.h"
#include "DeferredLayerUpdater.h"
+#include "LightingInfo.h"
#include "Readback.h"
#include "ShaderCache.h"
-#include "LightingInfo.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
#include "VkInteropFunctorDrawable.h"
#include "renderstate/RenderState.h"
#include "renderthread/Frame.h"
+#include "utils/TraceUtils.h"
#include <SkSurface.h>
#include <SkTypes.h>
@@ -73,8 +74,6 @@
LightingInfo::updateLighting(lightGeometry, lightInfo);
renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
mVkSurface->getCurrentPreTransform());
- ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
- layerUpdateQueue->clear();
// Draw visual debugging features
if (CC_UNLIKELY(Properties::showDirtyRegions ||
@@ -82,9 +81,14 @@
SkCanvas* profileCanvas = backBuffer->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
- profileCanvas->flush();
}
+ {
+ ATRACE_NAME("flush commands");
+ mVkManager.finishFrame(backBuffer.get());
+ }
+ layerUpdateQueue->clear();
+
// Log memory statistics
if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
dumpResourceCacheUsage();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 3e7ce36..e93824d 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -31,6 +31,7 @@
#include "Properties.h"
#include "RenderThread.h"
+#include "pipeline/skia/ShaderCache.h"
#include "renderstate/RenderState.h"
#include "utils/TraceUtils.h"
@@ -476,17 +477,10 @@
}
}
-void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
- if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
- ATRACE_NAME("Finishing GPU work");
- mDeviceWaitIdle(mDevice);
- }
-
- VulkanSurface::NativeBufferInfo* bufferInfo = surface->getCurrentBufferInfo();
- if (!bufferInfo) {
- // If VulkanSurface::dequeueNativeBuffer failed earlier, then swapBuffers is a no-op.
- return;
- }
+void VulkanManager::finishFrame(SkSurface* surface) {
+ ATRACE_NAME("Vulkan finish frame");
+ ALOGE_IF(mSwapSemaphore != VK_NULL_HANDLE || mDestroySemaphoreContext != nullptr,
+ "finishFrame already has an outstanding semaphore");
VkExportSemaphoreCreateInfo exportInfo;
exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
@@ -499,32 +493,52 @@
semaphoreInfo.flags = 0;
VkSemaphore semaphore;
VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
- ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to create semaphore");
+ ALOGE_IF(VK_SUCCESS != err, "VulkanManager::makeSwapSemaphore(): Failed to create semaphore");
GrBackendSemaphore backendSemaphore;
backendSemaphore.initVulkan(semaphore);
- int fenceFd = -1;
- DestroySemaphoreInfo* destroyInfo =
- new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
GrFlushInfo flushInfo;
- flushInfo.fNumSemaphores = 1;
- flushInfo.fSignalSemaphores = &backendSemaphore;
- flushInfo.fFinishedProc = destroy_semaphore;
- flushInfo.fFinishedContext = destroyInfo;
- GrSemaphoresSubmitted submitted = bufferInfo->skSurface->flush(
- SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
- GrDirectContext* context = GrAsDirectContext(bufferInfo->skSurface->recordingContext());
+ if (err == VK_SUCCESS) {
+ mDestroySemaphoreContext = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
+ flushInfo.fNumSemaphores = 1;
+ flushInfo.fSignalSemaphores = &backendSemaphore;
+ flushInfo.fFinishedProc = destroy_semaphore;
+ flushInfo.fFinishedContext = mDestroySemaphoreContext;
+ } else {
+ semaphore = VK_NULL_HANDLE;
+ }
+ GrSemaphoresSubmitted submitted =
+ surface->flush(SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
+ GrDirectContext* context = GrAsDirectContext(surface->recordingContext());
ALOGE_IF(!context, "Surface is not backed by gpu");
context->submit();
- if (submitted == GrSemaphoresSubmitted::kYes) {
+ if (semaphore != VK_NULL_HANDLE) {
+ if (submitted == GrSemaphoresSubmitted::kYes) {
+ mSwapSemaphore = semaphore;
+ } else {
+ destroy_semaphore(mDestroySemaphoreContext);
+ mDestroySemaphoreContext = nullptr;
+ }
+ }
+ skiapipeline::ShaderCache::get().onVkFrameFlushed(context);
+}
+
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+ ATRACE_NAME("Finishing GPU work");
+ mDeviceWaitIdle(mDevice);
+ }
+
+ int fenceFd = -1;
+ if (mSwapSemaphore != VK_NULL_HANDLE) {
VkSemaphoreGetFdInfoKHR getFdInfo;
getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
getFdInfo.pNext = nullptr;
- getFdInfo.semaphore = semaphore;
+ getFdInfo.semaphore = mSwapSemaphore;
getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+ VkResult err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
} else {
ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
@@ -532,9 +546,11 @@
std::lock_guard<std::mutex> lock(mGraphicsQueueMutex);
mQueueWaitIdle(mGraphicsQueue);
}
- destroy_semaphore(destroyInfo);
+ destroy_semaphore(mDestroySemaphoreContext);
surface->presentCurrentBuffer(dirtyRect, fenceFd);
+ mSwapSemaphore = VK_NULL_HANDLE;
+ mDestroySemaphoreContext = nullptr;
}
void VulkanManager::destroySurface(VulkanSurface* surface) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 121afc9..0912369 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -69,6 +69,7 @@
void destroySurface(VulkanSurface* surface);
Frame dequeueNextBuffer(VulkanSurface* surface);
+ void finishFrame(SkSurface* surface);
void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
// Inserts a wait on fence command into the Vulkan command buffer.
@@ -200,6 +201,9 @@
SwapBehavior mSwapBehavior = SwapBehavior::Discard;
GrVkExtensions mExtensions;
uint32_t mDriverVersion = 0;
+
+ VkSemaphore mSwapSemaphore = VK_NULL_HANDLE;
+ void* mDestroySemaphoreContext = nullptr;
};
} /* namespace renderthread */
diff --git a/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java
index f1eb8fc..6633d24 100644
--- a/location/java/android/location/GnssAntennaInfo.java
+++ b/location/java/android/location/GnssAntennaInfo.java
@@ -39,11 +39,7 @@
/**
* Used for receiving GNSS antenna info from the GNSS engine.
- *
- * @deprecated Prefer to use a broadcast receiver for
- * {@link LocationManager#ACTION_GNSS_ANTENNA_INFOS_CHANGED}.
*/
- @Deprecated
public interface Listener {
/**
* Invoked on a change to GNSS antenna info.
diff --git a/location/java/android/location/IGnssAntennaInfoListener.aidl b/location/java/android/location/IGnssAntennaInfoListener.aidl
new file mode 100644
index 0000000..3cceea3
--- /dev/null
+++ b/location/java/android/location/IGnssAntennaInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.location;
+
+import android.location.GnssAntennaInfo;
+
+/**
+ * {@hide}
+ */
+oneway interface IGnssAntennaInfoListener {
+ void onGnssAntennaInfoChanged(in List<GnssAntennaInfo> antennaInfos);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 5e39660..6fa6536 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -26,6 +26,7 @@
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementRequest;
import android.location.IGeocodeListener;
+import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssStatusListener;
import android.location.IGnssNavigationMessageListener;
@@ -92,6 +93,9 @@
void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag, String listenerId);
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
+ void addGnssAntennaInfoListener(in IGnssAntennaInfoListener listener, String packageName, @nullable String attributionTag, String listenerId);
+ void removeGnssAntennaInfoListener(in IGnssAntennaInfoListener listener);
+
void addProviderRequestListener(in IProviderRequestListener listener);
void removeProviderRequestListener(in IProviderRequestListener listener);
@@ -117,7 +121,8 @@
boolean isLocationEnabledForUser(int userId);
void setLocationEnabledForUser(boolean enabled, int userId);
- void addTestProvider(String name, in ProviderProperties properties, String packageName, @nullable String attributionTag);
+ void addTestProvider(String name, in ProviderProperties properties,
+ in List<String> locationTags, String packageName, @nullable String attributionTag);
void removeTestProvider(String provider, String packageName, @nullable String attributionTag);
void setTestProviderLocation(String provider, in Location location, String packageName, @nullable String attributionTag);
void setTestProviderEnabled(String provider, boolean enabled, String packageName, @nullable String attributionTag);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index dd5b6e6..e73e915 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -43,10 +43,8 @@
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
@@ -76,6 +74,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -348,28 +347,6 @@
public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
/**
- * Broadcast intent action when GNSS antenna infos change. Includes an intent extra,
- * {@link #EXTRA_GNSS_ANTENNA_INFOS}, with an ArrayList of the new {@link GnssAntennaInfo}. This
- * may be read via {@link android.content.Intent#getParcelableArrayListExtra(String)}.
- *
- * @see #EXTRA_GNSS_ANTENNA_INFOS
- * @see #getGnssAntennaInfos()
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_GNSS_ANTENNA_INFOS_CHANGED =
- "android.location.action.GNSS_ANTENNA_INFOS_CHANGED";
-
- /**
- * Intent extra included with {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED} broadcasts, containing
- * the new ArrayList of {@link GnssAntennaInfo}. This may be read via
- * {@link android.content.Intent#getParcelableArrayListExtra(String)}.
- *
- * @see #ACTION_GNSS_ANTENNA_INFOS_CHANGED
- */
- public static final String EXTRA_GNSS_ANTENNA_INFOS =
- "android.location.extra.GNSS_ANTENNA_INFOS";
-
- /**
* Broadcast intent action for Settings app to inject a footer at the bottom of location
* settings. This is for use only by apps that are included in the system image.
*
@@ -1957,12 +1934,33 @@
* allowed} for your app.
*/
public void addTestProvider(@NonNull String provider, @NonNull ProviderProperties properties) {
+ addTestProvider(provider, properties, Collections.emptySet());
+ }
+
+ /**
+ * Creates a test location provider and adds it to the set of active providers. This provider
+ * will replace any provider with the same name that exists prior to this call.
+ *
+ * @param provider the provider name
+ * @param properties the provider properties
+ * @param extraAttributionTags additional attribution tags associated with this provider
+ *
+ * @throws IllegalArgumentException if provider is null
+ * @throws IllegalArgumentException if properties is null
+ * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
+ * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
+ * allowed} for your app.
+ */
+ public void addTestProvider(@NonNull String provider, @NonNull ProviderProperties properties,
+ @NonNull Set<String> extraAttributionTags) {
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(properties != null, "invalid null properties");
+ Preconditions.checkArgument(extraAttributionTags != null,
+ "invalid null extra attribution tags");
try {
- mService.addTestProvider(provider, properties, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mService.addTestProvider(provider, properties, new ArrayList<>(extraAttributionTags),
+ mContext.getOpPackageName(), mContext.getFeatureId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2638,10 +2636,11 @@
}
/**
- * Registers a GNSS antenna info listener. GNSS antenna info updates will only be received while
- * the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground.
+ * Registers a GNSS antenna info listener that will receive all changes to antenna info. Use
+ * {@link #getGnssAntennaInfos()} to get current antenna info.
*
- * <p>Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}.
+ * <p>Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}. If
+ * unsupported, the listener will never be invoked.
*
* <p>Prior to Android S, this requires the {@link Manifest.permission#ACCESS_FINE_LOCATION}
* permission.
@@ -2652,10 +2651,7 @@
*
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if listener is null
- *
- * @deprecated Prefer to use a receiver for {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED}.
*/
- @Deprecated
public boolean registerAntennaInfoListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull GnssAntennaInfo.Listener listener) {
@@ -2665,13 +2661,10 @@
}
/**
- * Unregisters a GNSS Antenna Info listener.
+ * Unregisters a GNSS antenna info listener.
*
* @param listener a {@link GnssAntennaInfo.Listener} object to remove
- *
- * @deprecated Prefer to use a receiver for {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED}.
*/
- @Deprecated
public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) {
GnssLazyLoader.sGnssAntennaInfoListeners.removeListener(listener);
}
@@ -2988,14 +2981,17 @@
}
@Override
- protected void registerTransport(GnssAntennaInfoTransport transport) {
- transport.getContext().registerReceiver(transport,
- new IntentFilter(ACTION_GNSS_ANTENNA_INFOS_CHANGED));
+ protected void registerTransport(GnssAntennaInfoTransport transport)
+ throws RemoteException {
+ getService().addGnssAntennaInfoListener(transport, transport.getPackage(),
+ transport.getAttributionTag(),
+ AppOpsManager.toReceiverId(transport.getListener()));
}
@Override
- protected void unregisterTransport(GnssAntennaInfoTransport transport) {
- transport.getContext().unregisterReceiver(transport);
+ protected void unregisterTransport(GnssAntennaInfoTransport transport)
+ throws RemoteException {
+ getService().removeGnssAntennaInfoListener(transport);
}
}
@@ -3355,11 +3351,12 @@
}
}
- private static class GnssAntennaInfoTransport extends BroadcastReceiver implements
+ private static class GnssAntennaInfoTransport extends IGnssAntennaInfoListener.Stub implements
ListenerTransport<GnssAntennaInfo.Listener> {
private final Executor mExecutor;
- private final Context mContext;
+ private final String mPackageName;
+ private final String mAttributionTag;
private volatile @Nullable GnssAntennaInfo.Listener mListener;
@@ -3368,12 +3365,17 @@
Preconditions.checkArgument(executor != null, "invalid null executor");
Preconditions.checkArgument(listener != null, "invalid null listener");
mExecutor = executor;
- mContext = context;
+ mPackageName = context.getPackageName();
+ mAttributionTag = context.getAttributionTag();
mListener = listener;
}
- public Context getContext() {
- return mContext;
+ public String getPackage() {
+ return mPackageName;
+ }
+
+ public String getAttributionTag() {
+ return mAttributionTag;
}
@Override
@@ -3387,12 +3389,8 @@
}
@Override
- public void onReceive(Context context, Intent intent) {
- ArrayList<GnssAntennaInfo> infos = intent.getParcelableArrayListExtra(
- EXTRA_GNSS_ANTENNA_INFOS);
- if (infos != null) {
- execute(mExecutor, callback -> callback.onGnssAntennaInfoReceived(infos));
- }
+ public void onGnssAntennaInfoChanged(List<GnssAntennaInfo> antennaInfos) {
+ execute(mExecutor, callback -> callback.onGnssAntennaInfoReceived(antennaInfos));
}
}
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index a6a0e7a..763835c 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -21,6 +21,10 @@
import android.annotation.Nullable;
import android.location.util.identity.CallerIdentity;
+import com.android.internal.annotations.Immutable;
+
+import java.util.Set;
+
/**
* Location manager local system service interface.
*
@@ -39,6 +43,21 @@
}
/**
+ * Interface for getting callbacks when a location provider's location tags change.
+ *
+ * @see LocationTagInfo
+ */
+ public interface OnProviderLocationTagsChangeListener {
+
+ /**
+ * Called when the location tags for a provider change.
+ *
+ * @param providerLocationTagInfo The tag info for a provider.
+ */
+ void onLocationTagsChanged(@NonNull LocationTagInfo providerLocationTagInfo);
+ }
+
+ /**
* Returns true if the given provider is enabled for the given user.
*
* @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
@@ -88,4 +107,60 @@
* provider, and the elapsed nanos since boot the current time was computed at.
*/
public abstract @Nullable LocationTime getGnssTimeMillis();
+
+ /**
+ * Sets a listener for changes in the location providers' tags. Passing
+ * {@code null} clears the current listener.
+ *
+ * @param listener The listener.
+ */
+ public abstract void setOnProviderLocationTagsChangeListener(
+ @Nullable OnProviderLocationTagsChangeListener listener);
+
+ /**
+ * This class represents the location permission tags used by the location provider
+ * packages in a given UID. These tags are strictly used for accessing state guarded
+ * by the location permission(s) by a location provider which are required for the
+ * provider to fulfill its function as being a location provider.
+ */
+ @Immutable
+ public static class LocationTagInfo {
+ private final int mUid;
+
+ @NonNull
+ private final String mPackageName;
+
+ @Nullable
+ private final Set<String> mLocationTags;
+
+ public LocationTagInfo(int uid, @NonNull String packageName,
+ @Nullable Set<String> locationTags) {
+ mUid = uid;
+ mPackageName = packageName;
+ mLocationTags = locationTags;
+ }
+
+ /**
+ * @return The UID for which tags are related.
+ */
+ public int getUid() {
+ return mUid;
+ }
+
+ /**
+ * @return The package for which tags are related.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * @return The tags for the package used for location related accesses.
+ */
+ @Nullable
+ public Set<String> getTags() {
+ return mLocationTags;
+ }
+ }
}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index bb1dbd4..7e729d8 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1264,6 +1264,8 @@
*
* @param usage one of the {@link AudioAttributes} usage constants
* @return string representing the {@link AudioAttributes} usage constant passed as a parameter
+ *
+ * @hide
*/
@NonNull
public static String usageToString(@AttributeSdkUsage int usage) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f87f90d..b2de49d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -568,7 +568,7 @@
public static final int FLAG_FROM_KEY = 1 << 12;
/** @hide */
- @IntDef(flag = false, prefix = "FLAG", value = {
+ @IntDef(flag = true, prefix = "FLAG", value = {
FLAG_SHOW_UI,
FLAG_ALLOW_RINGER_MODES,
FLAG_PLAY_SOUND,
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index b196437..bf04b66 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -275,6 +275,12 @@
private AudioAttributes mAudioAttributes;
private boolean mIsSubmixFullVolume = false;
+ /**
+ * The log session id used for metrics.
+ * A null or empty string here means it is not set.
+ */
+ private String mLogSessionId;
+
//---------------------------------------------------------
// Constructor, Finalize
//--------------------
@@ -1913,6 +1919,25 @@
return native_set_preferred_microphone_field_dimension(zoom) == AudioSystem.SUCCESS;
}
+ /**
+ * Sets a string handle to this AudioRecord for metrics collection.
+ *
+ * @param logSessionId a string which is used to identify this object
+ * to the metrics service. Proper generated Ids must be obtained
+ * from the Java metrics service and should be considered opaque.
+ * Use null to remove the logSessionId association.
+ * @throws IllegalStateException if AudioRecord not initialized.
+ *
+ * @hide
+ */
+ public void setLogSessionId(@Nullable String logSessionId) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw new IllegalStateException("AudioRecord not initialized");
+ }
+ native_setLogSessionId(logSessionId);
+ mLogSessionId = logSessionId;
+ }
+
//---------------------------------------------------------
// Interface definitions
//--------------------
@@ -2072,6 +2097,8 @@
private native int native_set_preferred_microphone_direction(int direction);
private native int native_set_preferred_microphone_field_dimension(float zoom);
+ private native void native_setLogSessionId(@Nullable String logSessionId);
+
//---------------------------------------------------------
// Utility methods
//------------------
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6fcb756..88731d2 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -567,6 +567,7 @@
/**
* The log session id used for metrics.
+ * A null or empty string here means it is not set.
*/
private String mLogSessionId;
@@ -928,12 +929,21 @@
private final int mSyncId;
/**
+ * A special content id for {@link #TunerConfiguration(int, int)}
+ * indicating audio is delivered
+ * from an {@code AudioTrack} write, not tunneled from the tuner stack.
+ */
+ public static final int CONTENT_ID_NONE = 0;
+
+ /**
* Constructs a TunerConfiguration instance for use in {@link AudioTrack.Builder}
*
* @param contentId selects the audio stream to use.
* The contentId may be obtained from
- * {@link android.media.tv.tuner.filter.Filter#getId()}.
- * This is always a positive number.
+ * {@link android.media.tv.tuner.filter.Filter#getId()},
+ * such obtained id is always a positive number.
+ * If audio is to be delivered through an {@code AudioTrack} write
+ * then {@code CONTENT_ID_NONE} may be used.
* @param syncId selects the clock to use for synchronization
* of audio with other streams such as video.
* The syncId may be obtained from
@@ -942,10 +952,10 @@
*/
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public TunerConfiguration(
- @IntRange(from = 1) int contentId, @IntRange(from = 1)int syncId) {
- if (contentId < 1) {
+ @IntRange(from = 0) int contentId, @IntRange(from = 1)int syncId) {
+ if (contentId < 0) {
throw new IllegalArgumentException(
- "contentId " + contentId + " must be positive");
+ "contentId " + contentId + " must be positive or CONTENT_ID_NONE");
}
if (syncId < 1) {
throw new IllegalArgumentException("syncId " + syncId + " must be positive");
@@ -3526,8 +3536,9 @@
native_enableDeviceCallback();
return true;
} catch (IllegalStateException e) {
- // Fail silently as track state could have changed in between start
- // and enabling routing callback, return false to indicate not enabled
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "testEnableNativeRoutingCallbacks failed", e);
+ }
}
}
return false;
@@ -3577,7 +3588,7 @@
Handler handler) {
synchronized (mRoutingChangeListeners) {
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
- testEnableNativeRoutingCallbacksLocked();
+ mEnableSelfRoutingMonitor = testEnableNativeRoutingCallbacksLocked();
mRoutingChangeListeners.put(
listener, new NativeRoutingEventHandlerDelegate(this, listener,
handler != null ? handler : new Handler(mInitializationLooper)));
@@ -3977,12 +3988,14 @@
* Sets a string handle to this AudioTrack for metrics collection.
*
* @param logSessionId a string which is used to identify this object
- * to the metrics service.
+ * to the metrics service. Proper generated Ids must be obtained
+ * from the Java metrics service and should be considered opaque.
+ * Use null to remove the logSessionId association.
* @throws IllegalStateException if AudioTrack not initialized.
*
* @hide
*/
- public void setLogSessionId(@NonNull String logSessionId) {
+ public void setLogSessionId(@Nullable String logSessionId) {
if (mState == STATE_UNINITIALIZED) {
throw new IllegalStateException("track not initialized");
}
@@ -4225,7 +4238,7 @@
private native int native_get_audio_description_mix_level_db(float[] level);
private native int native_set_dual_mono_mode(int dualMonoMode);
private native int native_get_dual_mono_mode(int[] dualMonoMode);
- private native void native_setLogSessionId(@NonNull String logSessionId);
+ private native void native_setLogSessionId(@Nullable String logSessionId);
/**
* Sets the audio service Player Interface Id.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4d7ed11..06d0eb0 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -19,6 +19,7 @@
import static android.media.Utils.intersectSortedDistinctRanges;
import static android.media.Utils.sortDistinctRanges;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -1133,6 +1134,7 @@
* in the ranges returned by {@link #getInputChannelCountRanges}
*
*/
+ @IntRange(from = 1, to = 255)
public int getMaxInputChannelCount() {
int overall_max = 0;
for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
@@ -1151,6 +1153,7 @@
* This returns the lowest channel count in the ranges returned by
* {@link #getInputChannelCountRanges}.
*/
+ @IntRange(from = 1, to = 255)
public int getMinInputChannelCount() {
int overall_min = MAX_INPUT_CHANNEL_COUNT;
for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 67f1660..f8a642a 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -980,6 +980,74 @@
public static final String KEY_BITRATE_MODE = "bitrate-mode";
/**
+ * A key describing the maximum Quantization Parameter allowed for encoding video.
+ * This key applies to all three video frame types (I, P, and B). This value fills
+ * in for any of the frame-specific #KEY_VIDEO_QP_I_MAX, #KEY_VIDEO_QP_P_MAX, or
+ * #KEY_VIDEO_QP_B_MAX keys that are not specified
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_MAX = "video-qp-max";
+
+ /**
+ * A key describing the maximum Quantization Parameter allowed for encoding video.
+ * This key applies to all three video frame types (I, P, and B). This value fills
+ * in for any of the frame-specific #KEY_VIDEO_QP_I_MIN, #KEY_VIDEO_QP_P_MIN, or
+ * #KEY_VIDEO_QP_B_MIN keys that are not specified
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_MIN = "video-qp-min";
+
+ /**
+ * A key describing the maximum Quantization Parameter allowed for encoding video.
+ * This value applies to video I-frames.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_I_MAX = "video-qp-i-max";
+
+ /**
+ * A key describing the minimum Quantization Parameter allowed for encoding video.
+ * This value applies to video I-frames.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_I_MIN = "video-qp-i-min";
+
+ /**
+ * A key describing the maximum Quantization Parameter allowed for encoding video.
+ * This value applies to video P-frames.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max";
+
+ /**
+ * A key describing the minimum Quantization Parameter allowed for encoding video.
+ * This value applies to video P-frames.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
+
+ /**
+ * A key describing the maximum Quantization Parameter allowed for encoding video.
+ * This value applies to video B-frames.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_B_MAX = "video-qp-b-max";
+
+ /**
+ * A key describing the minimum Quantization Parameter allowed for encoding video.
+ * This value applies to video B-frames.
+ *
+ * The associated value is an integer.
+ */
+ public static final String KEY_VIDEO_QP_B_MIN = "video-qp-b-min";
+
+ /**
* A key describing the audio session ID of the AudioTrack associated
* to a tunneled video codec.
* The associated value is an integer.
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index f3cee17..9176dae 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1360,6 +1360,7 @@
private void startImpl() {
baseStart(0); // unknown device at this point
stayAwake(true);
+ tryToEnableNativeRoutingCallback();
_start();
}
@@ -1385,6 +1386,7 @@
stayAwake(false);
_stop();
baseStop();
+ tryToDisableNativeRoutingCallback();
}
private native void _stop() throws IllegalStateException;
@@ -1526,8 +1528,9 @@
native_enableDeviceCallback(true);
return true;
} catch (IllegalStateException e) {
- // Fail silently as media player state could have changed in between start
- // and enabling routing callback, return false to indicate not enabled
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "testEnableNativeRoutingCallbacks failed", e);
+ }
}
}
return false;
@@ -1590,7 +1593,7 @@
Handler handler) {
synchronized (mRoutingChangeListeners) {
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
- testEnableNativeRoutingCallbacksLocked();
+ mEnableSelfRoutingMonitor = testEnableNativeRoutingCallbacksLocked();
mRoutingChangeListeners.put(
listener, new NativeRoutingEventHandlerDelegate(this, listener,
handler != null ? handler : mEventHandler));
@@ -3483,9 +3486,6 @@
case MEDIA_STOPPED:
{
- tryToDisableNativeRoutingCallback();
- // FIXME see b/179218630
- //baseStop();
TimeProvider timeProvider = mTimeProvider;
if (timeProvider != null) {
timeProvider.onStopped();
@@ -3494,18 +3494,9 @@
break;
case MEDIA_STARTED:
- {
- // FIXME see b/179218630
- //baseStart(native_getRoutedDeviceId());
- tryToEnableNativeRoutingCallback();
- }
// fall through
case MEDIA_PAUSED:
{
- // FIXME see b/179218630
- //if (msg.what == MEDIA_PAUSED) {
- // basePause();
- //}
TimeProvider timeProvider = mTimeProvider;
if (timeProvider != null) {
timeProvider.onPaused(msg.what == MEDIA_PAUSED);
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index dc476b8..96bffee117 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -38,9 +38,7 @@
interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback sessionCb, String tag,
in Bundle sessionInfo, int userId);
- void notifySession2Created(in Session2Token sessionToken);
List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
- ParceledListSlice getSession2Tokens(int userId);
void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
boolean needWakeLock);
boolean dispatchMediaKeyEventToSessionAsSystemService(String packageName,
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index aa0f7fd..98a13cf 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -25,9 +25,9 @@
import android.annotation.SystemService;
import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.ParceledListSlice;
import android.media.AudioManager;
import android.media.IRemoteSessionCallback;
+import android.media.MediaCommunicationManager;
import android.media.MediaFrameworkPlatformInitializer;
import android.media.MediaSession2;
import android.media.Session2Token;
@@ -84,6 +84,7 @@
public static final int RESULT_MEDIA_KEY_HANDLED = 1;
private final ISessionManager mService;
+ private final MediaCommunicationManager mCommunicationManager;
private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub =
new OnMediaKeyEventDispatchedListenerStub();
private final OnMediaKeyEventSessionChangedListenerStub
@@ -128,6 +129,8 @@
.getMediaServiceManager()
.getMediaSessionServiceRegisterer()
.get());
+ mCommunicationManager = (MediaCommunicationManager) context
+ .getSystemService(Context.MEDIA_COMMUNICATION_SERVICE);
}
/**
@@ -164,17 +167,11 @@
* {@link MediaSession2.Builder} instead.
*
* @param token newly created session2 token
+ * @deprecated Don't use this method. A new media session is notified automatically.
*/
+ @Deprecated
public void notifySession2Created(@NonNull Session2Token token) {
- Objects.requireNonNull(token, "token shouldn't be null");
- if (token.getType() != Session2Token.TYPE_SESSION) {
- throw new IllegalArgumentException("token's type should be TYPE_SESSION");
- }
- try {
- mService.notifySession2Created(token);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ // Does nothing
}
/**
@@ -255,37 +252,7 @@
*/
@NonNull
public List<Session2Token> getSession2Tokens() {
- return getSession2Tokens(UserHandle.myUserId());
- }
-
- /**
- * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
- * given user.
- * <p>
- * The calling application needs to hold the
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
- * retrieve session tokens for user ids that do not belong to current process.
- *
- * @param userHandle The user handle to fetch sessions for.
- * @return A list of {@link Session2Token}
- * @hide
- */
- @NonNull
- @SuppressLint("UserHandle")
- public List<Session2Token> getSession2Tokens(@NonNull UserHandle userHandle) {
- Objects.requireNonNull(userHandle, "userHandle shouldn't be null");
- return getSession2Tokens(userHandle.getIdentifier());
-
- }
-
- private List<Session2Token> getSession2Tokens(int userId) {
- try {
- ParceledListSlice slice = mService.getSession2Tokens(userId);
- return slice == null ? new ArrayList<>() : slice.getList();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get session tokens", e);
- }
- return new ArrayList<>();
+ return mCommunicationManager.getSession2Tokens();
}
/**
@@ -534,8 +501,7 @@
}
if (shouldRegisterCallback) {
try {
- mService.registerRemoteSessionCallback(
- mRemoteSessionCallbackStub);
+ mService.registerRemoteSessionCallback(mRemoteSessionCallbackStub);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register remote volume controller callback", e);
}
diff --git a/media/java/android/media/soundtrigger/OWNERS b/media/java/android/media/soundtrigger/OWNERS
index 6a351d3..e5d0370 100644
--- a/media/java/android/media/soundtrigger/OWNERS
+++ b/media/java/android/media/soundtrigger/OWNERS
@@ -1 +1,2 @@
+ytai@google.com
elaurent@google.com
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 042d02f..1d2657a 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -144,11 +144,6 @@
native_remove_storage(storage.getStorageId());
}
- public static void configure(boolean usePtp) {
- native_configure(usePtp);
- }
-
- public static native final void native_configure(boolean usePtp);
private native final void native_setup(
MtpDatabase database,
FileDescriptor controlFd,
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 3669bf4..7562d39 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -561,7 +561,7 @@
const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent");
- jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJJ)V");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJJI)V");
for (int i = 0; i < events.size(); i++) {
auto event = events[i];
@@ -614,7 +614,7 @@
const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent");
- jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJIJ)V");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJIJII)V");
for (int i = 0; i < events.size(); i++) {
auto event = events[i];
@@ -1128,7 +1128,7 @@
bool isHighPriority = message.isHighPriority();
env->CallVoidMethod(
frontend,
- env->GetMethodID(clazz, "onPriorityReported", "(B)V"),
+ env->GetMethodID(clazz, "onPriorityReported", "(Z)V"),
isHighPriority);
break;
}
@@ -3571,26 +3571,28 @@
.tpid = tpid,
};
- DemuxTsFilterType tsType = static_cast<DemuxTsFilterType>(subtype);
- switch (tsType) {
- case DemuxTsFilterType::SECTION:
- tsFilterSettings.filterSettings.section(
- getFilterSectionSettings(env, settingsObj));
- break;
- case DemuxTsFilterType::AUDIO:
- case DemuxTsFilterType::VIDEO:
- tsFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
- break;
- case DemuxTsFilterType::PES:
- tsFilterSettings.filterSettings.pesData(
- getFilterPesDataSettings(env, settingsObj));
- break;
- case DemuxTsFilterType::RECORD:
- tsFilterSettings.filterSettings.record(
- getFilterRecordSettings(env, settingsObj));
- break;
- default:
- break;
+ if (settingsObj != NULL) {
+ DemuxTsFilterType tsType = static_cast<DemuxTsFilterType>(subtype);
+ switch (tsType) {
+ case DemuxTsFilterType::SECTION:
+ tsFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ case DemuxTsFilterType::AUDIO:
+ case DemuxTsFilterType::VIDEO:
+ tsFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+ break;
+ case DemuxTsFilterType::PES:
+ tsFilterSettings.filterSettings.pesData(
+ getFilterPesDataSettings(env, settingsObj));
+ break;
+ case DemuxTsFilterType::RECORD:
+ tsFilterSettings.filterSettings.record(
+ getFilterRecordSettings(env, settingsObj));
+ break;
+ default:
+ break;
+ }
}
filterSettings.ts(tsFilterSettings);
break;
@@ -3602,60 +3604,55 @@
DemuxMmtpFilterSettings mmtpFilterSettings {
.mmtpPid = mmtpPid,
};
- DemuxMmtpFilterType mmtpType = static_cast<DemuxMmtpFilterType>(subtype);
- switch (mmtpType) {
- case DemuxMmtpFilterType::SECTION:
- mmtpFilterSettings.filterSettings.section(
- getFilterSectionSettings(env, settingsObj));
- break;
- case DemuxMmtpFilterType::AUDIO:
- case DemuxMmtpFilterType::VIDEO:
- mmtpFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
- break;
- case DemuxMmtpFilterType::PES:
- mmtpFilterSettings.filterSettings.pesData(
- getFilterPesDataSettings(env, settingsObj));
- break;
- case DemuxMmtpFilterType::RECORD:
- mmtpFilterSettings.filterSettings.record(
- getFilterRecordSettings(env, settingsObj));
- break;
- case DemuxMmtpFilterType::DOWNLOAD:
- mmtpFilterSettings.filterSettings.download(
- getFilterDownloadSettings(env, settingsObj));
- break;
- default:
- break;
+
+ if (settingsObj != NULL) {
+ DemuxMmtpFilterType mmtpType = static_cast<DemuxMmtpFilterType>(subtype);
+ switch (mmtpType) {
+ case DemuxMmtpFilterType::SECTION:
+ mmtpFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::AUDIO:
+ case DemuxMmtpFilterType::VIDEO:
+ mmtpFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::PES:
+ mmtpFilterSettings.filterSettings.pesData(
+ getFilterPesDataSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::RECORD:
+ mmtpFilterSettings.filterSettings.record(
+ getFilterRecordSettings(env, settingsObj));
+ break;
+ case DemuxMmtpFilterType::DOWNLOAD:
+ mmtpFilterSettings.filterSettings.download(
+ getFilterDownloadSettings(env, settingsObj));
+ break;
+ default:
+ break;
+ }
}
filterSettings.mmtp(mmtpFilterSettings);
break;
}
case DemuxFilterMainType::IP: {
DemuxIpAddress ipAddr = getDemuxIpAddress(env, filterConfigObj);
-
DemuxIpFilterSettings ipFilterSettings {
.ipAddr = ipAddr,
};
+
DemuxIpFilterType ipType = static_cast<DemuxIpFilterType>(subtype);
- switch (ipType) {
- case DemuxIpFilterType::SECTION: {
- ipFilterSettings.filterSettings.section(
- getFilterSectionSettings(env, settingsObj));
- break;
- }
- case DemuxIpFilterType::IP: {
- jclass clazz = env->FindClass(
- "android/media/tv/tuner/filter/IpFilterConfiguration");
- bool bPassthrough = static_cast<bool>(
- env->GetBooleanField(
- filterConfigObj, env->GetFieldID(
- clazz, "mPassthrough", "Z")));
- ipFilterSettings.filterSettings.bPassthrough(bPassthrough);
- break;
- }
- default: {
- break;
- }
+ if (ipType == DemuxIpFilterType::SECTION && settingsObj != NULL) {
+ ipFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ } else if (ipType == DemuxIpFilterType::IP) {
+ jclass clazz = env->FindClass(
+ "android/media/tv/tuner/filter/IpFilterConfiguration");
+ bool bPassthrough = static_cast<bool>(
+ env->GetBooleanField(
+ filterConfigObj, env->GetFieldID(
+ clazz, "mPassthrough", "Z")));
+ ipFilterSettings.filterSettings.bPassthrough(bPassthrough);
}
filterSettings.ip(ipFilterSettings);
break;
@@ -3672,24 +3669,17 @@
.packetType = packetType,
.isCompressedIpPacket = isCompressedIpPacket,
};
+
DemuxTlvFilterType tlvType = static_cast<DemuxTlvFilterType>(subtype);
- switch (tlvType) {
- case DemuxTlvFilterType::SECTION: {
- tlvFilterSettings.filterSettings.section(
- getFilterSectionSettings(env, settingsObj));
- break;
- }
- case DemuxTlvFilterType::TLV: {
- bool bPassthrough = static_cast<bool>(
- env->GetBooleanField(
- filterConfigObj, env->GetFieldID(
- clazz, "mPassthrough", "Z")));
- tlvFilterSettings.filterSettings.bPassthrough(bPassthrough);
- break;
- }
- default: {
- break;
- }
+ if (tlvType == DemuxTlvFilterType::SECTION && settingsObj != NULL) {
+ tlvFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ } else if (tlvType == DemuxTlvFilterType::TLV) {
+ bool bPassthrough = static_cast<bool>(
+ env->GetBooleanField(
+ filterConfigObj, env->GetFieldID(
+ clazz, "mPassthrough", "Z")));
+ tlvFilterSettings.filterSettings.bPassthrough(bPassthrough);
}
filterSettings.tlv(tlvFilterSettings);
break;
@@ -3704,14 +3694,17 @@
.packetType = packetType,
.lengthType = lengthType,
};
- DemuxAlpFilterType alpType = static_cast<DemuxAlpFilterType>(subtype);
- switch (alpType) {
- case DemuxAlpFilterType::SECTION:
- alpFilterSettings.filterSettings.section(
- getFilterSectionSettings(env, settingsObj));
- break;
- default:
- break;
+
+ if (settingsObj != NULL) {
+ DemuxAlpFilterType alpType = static_cast<DemuxAlpFilterType>(subtype);
+ switch (alpType) {
+ case DemuxAlpFilterType::SECTION:
+ alpFilterSettings.filterSettings.section(
+ getFilterSectionSettings(env, settingsObj));
+ break;
+ default:
+ break;
+ }
}
filterSettings.alp(alpFilterSettings);
break;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/AudioAttributesUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/AudioAttributesUnitTest.java
new file mode 100644
index 0000000..3a4bec0
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/AudioAttributesUnitTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import static org.junit.Assert.assertEquals;
+
+import android.media.AudioAttributes;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class AudioAttributesUnitTest {
+
+ @Test
+ public void testUsageToString_returnCorrectStrings() {
+ assertEquals("USAGE_UNKNOWN", AudioAttributes.usageToString(AudioAttributes.USAGE_UNKNOWN));
+ assertEquals("USAGE_MEDIA", AudioAttributes.usageToString(AudioAttributes.USAGE_MEDIA));
+ assertEquals("USAGE_VOICE_COMMUNICATION",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_VOICE_COMMUNICATION));
+ assertEquals("USAGE_VOICE_COMMUNICATION_SIGNALLING",
+ AudioAttributes.usageToString(
+ AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING));
+ assertEquals("USAGE_ALARM", AudioAttributes.usageToString(AudioAttributes.USAGE_ALARM));
+ assertEquals("USAGE_NOTIFICATION",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_NOTIFICATION));
+ assertEquals("USAGE_NOTIFICATION_RINGTONE",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_NOTIFICATION_RINGTONE));
+ assertEquals("USAGE_NOTIFICATION_COMMUNICATION_REQUEST",
+ AudioAttributes.usageToString(
+ AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST));
+ assertEquals("USAGE_NOTIFICATION_COMMUNICATION_INSTANT",
+ AudioAttributes.usageToString(
+ AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT));
+ assertEquals("USAGE_NOTIFICATION_COMMUNICATION_DELAYED",
+ AudioAttributes.usageToString(
+ AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED));
+ assertEquals("USAGE_NOTIFICATION_EVENT",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_NOTIFICATION_EVENT));
+ assertEquals("USAGE_ASSISTANCE_ACCESSIBILITY",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY));
+ assertEquals("USAGE_ASSISTANCE_NAVIGATION_GUIDANCE",
+ AudioAttributes.usageToString(
+ AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+ assertEquals("USAGE_ASSISTANCE_SONIFICATION",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION));
+ assertEquals("USAGE_GAME", AudioAttributes.usageToString(AudioAttributes.USAGE_GAME));
+ assertEquals("USAGE_ASSISTANT",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_ASSISTANT));
+ assertEquals("USAGE_CALL_ASSISTANT",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_CALL_ASSISTANT));
+ assertEquals("USAGE_EMERGENCY",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_EMERGENCY));
+ assertEquals("USAGE_SAFETY", AudioAttributes.usageToString(AudioAttributes.USAGE_SAFETY));
+ assertEquals("USAGE_VEHICLE_STATUS",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_VEHICLE_STATUS));
+ assertEquals("USAGE_ANNOUNCEMENT",
+ AudioAttributes.usageToString(AudioAttributes.USAGE_ANNOUNCEMENT));
+ }
+
+ @Test
+ public void testUsageToString_unknownUsage() {
+ assertEquals("unknown usage -1", AudioAttributes.usageToString(-1));
+ }
+}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 28072ca..f1a98ad 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -143,7 +143,7 @@
}
static void notifyDevicesChanged() {
- if (sInstance != null && !sInstance.isFinishing()) {
+ if (sInstance != null && sInstance.mDevicesAdapter != null && !sInstance.isFinishing()) {
sInstance.mDevicesAdapter.notifyDataSetChanged();
}
}
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index c7e261c..86b85e83 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -58,3 +58,28 @@
"//packages/modules/Connectivity:__subpackages__",
],
}
+
+java_sdk_library {
+ name: "framework-connectivity",
+ api_only: true,
+ defaults: ["framework-module-defaults"],
+ // TODO: build against module API
+ platform_apis: true,
+ srcs: [
+ ":framework-connectivity-sources",
+ ],
+ aidl: {
+ include_dirs: [
+ // Include directories for parcelables that are part of the stable API, and need a
+ // one-line "parcelable X" .aidl declaration to be used in AIDL interfaces.
+ // TODO(b/180293679): remove these dependencies as they should not be necessary once
+ // the module builds against API (the parcelable declarations exist in framework.aidl)
+ "frameworks/base/core/java", // For framework parcelables
+ "frameworks/native/aidl/binder", // For PersistableBundle.aidl
+ ],
+ },
+ libs: [
+ "unsupportedappusage",
+ ],
+ permitted_packages: ["android.net", "com.android.connectivity.aidl"],
+}
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
new file mode 100644
index 0000000..31b8fc8
--- /dev/null
+++ b/packages/Connectivity/framework/api/current.txt
@@ -0,0 +1,470 @@
+// Signature format: 2.0
+package android.net {
+
+ public class CaptivePortal implements android.os.Parcelable {
+ method public int describeContents();
+ method public void ignoreNetwork();
+ method public void reportCaptivePortalDismissed();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
+ }
+
+ public class ConnectivityDiagnosticsManager {
+ method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ }
+
+ public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
+ method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
+ method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
+ method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
+ }
+
+ public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+ method public int describeContents();
+ method @NonNull public android.os.PersistableBundle getAdditionalInfo();
+ method @NonNull public android.net.LinkProperties getLinkProperties();
+ method @NonNull public android.net.Network getNetwork();
+ method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public long getReportTimestamp();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
+ field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
+ field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
+ field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+ field public static final int NETWORK_PROBE_DNS = 4; // 0x4
+ field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
+ field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
+ field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
+ field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
+ field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
+ field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
+ field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
+ field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
+ }
+
+ public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
+ ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+ method public int describeContents();
+ method public int getDetectionMethod();
+ method @NonNull public android.net.LinkProperties getLinkProperties();
+ method @NonNull public android.net.Network getNetwork();
+ method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public long getReportTimestamp();
+ method @NonNull public android.os.PersistableBundle getStallDetails();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
+ field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+ field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
+ field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+ field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
+ field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
+ }
+
+ public class ConnectivityManager {
+ method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public boolean bindProcessToNetwork(@Nullable android.net.Network);
+ method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
+ method @Deprecated public boolean getBackgroundDataSetting();
+ method @Nullable public android.net.Network getBoundNetworkForProcess();
+ method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
+ method @Nullable public android.net.ProxyInfo getDefaultProxy();
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
+ method @Nullable public byte[] getNetworkWatchlistConfigHash();
+ method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
+ method public int getRestrictBackgroundStatus();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
+ method public boolean isDefaultNetworkActive();
+ method @Deprecated public static boolean isNetworkTypeValid(int);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+ method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
+ method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
+ method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
+ method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
+ method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated public void setNetworkPreference(int);
+ method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
+ method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+ method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
+ field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+ field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
+ field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
+ field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+ field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
+ field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+ field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
+ field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
+ field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
+ field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
+ field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
+ field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
+ field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
+ field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
+ field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
+ field public static final String EXTRA_REASON = "reason";
+ field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+ field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+ field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+ field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
+ field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
+ field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
+ field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
+ field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
+ field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
+ field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
+ field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
+ field @Deprecated public static final int TYPE_VPN = 17; // 0x11
+ field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
+ field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
+ }
+
+ public static class ConnectivityManager.NetworkCallback {
+ ctor public ConnectivityManager.NetworkCallback();
+ method public void onAvailable(@NonNull android.net.Network);
+ method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
+ method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
+ method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
+ method public void onLosing(@NonNull android.net.Network, int);
+ method public void onLost(@NonNull android.net.Network);
+ method public void onUnavailable();
+ }
+
+ public static interface ConnectivityManager.OnNetworkActiveListener {
+ method public void onNetworkActive();
+ }
+
+ public class DhcpInfo implements android.os.Parcelable {
+ ctor public DhcpInfo();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
+ field public int dns1;
+ field public int dns2;
+ field public int gateway;
+ field public int ipAddress;
+ field public int leaseDuration;
+ field public int netmask;
+ field public int serverAddress;
+ }
+
+ public final class DnsResolver {
+ method @NonNull public static android.net.DnsResolver getInstance();
+ method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+ method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+ method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
+ method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
+ field public static final int CLASS_IN = 1; // 0x1
+ field public static final int ERROR_PARSE = 0; // 0x0
+ field public static final int ERROR_SYSTEM = 1; // 0x1
+ field public static final int FLAG_EMPTY = 0; // 0x0
+ field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
+ field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
+ field public static final int FLAG_NO_RETRY = 1; // 0x1
+ field public static final int TYPE_A = 1; // 0x1
+ field public static final int TYPE_AAAA = 28; // 0x1c
+ }
+
+ public static interface DnsResolver.Callback<T> {
+ method public void onAnswer(@NonNull T, int);
+ method public void onError(@NonNull android.net.DnsResolver.DnsException);
+ }
+
+ public static class DnsResolver.DnsException extends java.lang.Exception {
+ field public final int code;
+ }
+
+ public class InetAddresses {
+ method public static boolean isNumericAddress(@NonNull String);
+ method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
+ }
+
+ public final class IpPrefix implements android.os.Parcelable {
+ method public boolean contains(@NonNull java.net.InetAddress);
+ method public int describeContents();
+ method @NonNull public java.net.InetAddress getAddress();
+ method @IntRange(from=0, to=128) public int getPrefixLength();
+ method @NonNull public byte[] getRawAddress();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
+ }
+
+ public class LinkAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.net.InetAddress getAddress();
+ method public int getFlags();
+ method @IntRange(from=0, to=128) public int getPrefixLength();
+ method public int getScope();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
+ }
+
+ public final class LinkProperties implements android.os.Parcelable {
+ ctor public LinkProperties();
+ method public boolean addRoute(@NonNull android.net.RouteInfo);
+ method public void clear();
+ method public int describeContents();
+ method @Nullable public java.net.Inet4Address getDhcpServerAddress();
+ method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+ method @Nullable public String getDomains();
+ method @Nullable public android.net.ProxyInfo getHttpProxy();
+ method @Nullable public String getInterfaceName();
+ method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
+ method public int getMtu();
+ method @Nullable public android.net.IpPrefix getNat64Prefix();
+ method @Nullable public String getPrivateDnsServerName();
+ method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
+ method public boolean isPrivateDnsActive();
+ method public boolean isWakeOnLanSupported();
+ method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
+ method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
+ method public void setDomains(@Nullable String);
+ method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+ method public void setInterfaceName(@Nullable String);
+ method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
+ method public void setMtu(int);
+ method public void setNat64Prefix(@Nullable android.net.IpPrefix);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
+ }
+
+ public final class MacAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
+ method @NonNull public static android.net.MacAddress fromString(@NonNull String);
+ method public int getAddressType();
+ method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
+ method public boolean isLocallyAssigned();
+ method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
+ method @NonNull public byte[] toByteArray();
+ method @NonNull public String toOuiString();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.net.MacAddress BROADCAST_ADDRESS;
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
+ field public static final int TYPE_BROADCAST = 3; // 0x3
+ field public static final int TYPE_MULTICAST = 2; // 0x2
+ field public static final int TYPE_UNICAST = 1; // 0x1
+ }
+
+ public class Network implements android.os.Parcelable {
+ method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
+ method public void bindSocket(java.net.Socket) throws java.io.IOException;
+ method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
+ method public int describeContents();
+ method public static android.net.Network fromNetworkHandle(long);
+ method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
+ method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
+ method public long getNetworkHandle();
+ method public javax.net.SocketFactory getSocketFactory();
+ method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
+ method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ ctor public NetworkCapabilities();
+ ctor public NetworkCapabilities(android.net.NetworkCapabilities);
+ method public int describeContents();
+ method public int getLinkDownstreamBandwidthKbps();
+ method public int getLinkUpstreamBandwidthKbps();
+ method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+ method public int getOwnerUid();
+ method public int getSignalStrength();
+ method @Nullable public android.net.TransportInfo getTransportInfo();
+ method public boolean hasCapability(int);
+ method public boolean hasTransport(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
+ field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
+ field public static final int NET_CAPABILITY_CBS = 5; // 0x5
+ field public static final int NET_CAPABILITY_DUN = 2; // 0x2
+ field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+ field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
+ field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
+ field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
+ field public static final int NET_CAPABILITY_IA = 7; // 0x7
+ field public static final int NET_CAPABILITY_IMS = 4; // 0x4
+ field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
+ field public static final int NET_CAPABILITY_MCX = 23; // 0x17
+ field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+ field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
+ field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
+ field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
+ field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
+ field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
+ field public static final int NET_CAPABILITY_RCS = 8; // 0x8
+ field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
+ field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19
+ field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
+ field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
+ field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
+ field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
+ field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
+ field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
+ field public static final int TRANSPORT_CELLULAR = 0; // 0x0
+ field public static final int TRANSPORT_ETHERNET = 3; // 0x3
+ field public static final int TRANSPORT_LOWPAN = 6; // 0x6
+ field public static final int TRANSPORT_VPN = 4; // 0x4
+ field public static final int TRANSPORT_WIFI = 1; // 0x1
+ field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
+ }
+
+ @Deprecated public class NetworkInfo implements android.os.Parcelable {
+ ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String);
+ method @Deprecated public int describeContents();
+ method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
+ method @Deprecated public String getExtraInfo();
+ method @Deprecated public String getReason();
+ method @Deprecated public android.net.NetworkInfo.State getState();
+ method @Deprecated public int getSubtype();
+ method @Deprecated public String getSubtypeName();
+ method @Deprecated public int getType();
+ method @Deprecated public String getTypeName();
+ method @Deprecated public boolean isAvailable();
+ method @Deprecated public boolean isConnected();
+ method @Deprecated public boolean isConnectedOrConnecting();
+ method @Deprecated public boolean isFailover();
+ method @Deprecated public boolean isRoaming();
+ method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String);
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
+ }
+
+ @Deprecated public enum NetworkInfo.DetailedState {
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
+ }
+
+ @Deprecated public enum NetworkInfo.State {
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
+ }
+
+ public class NetworkRequest implements android.os.Parcelable {
+ method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
+ method public int describeContents();
+ method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+ method public boolean hasCapability(int);
+ method public boolean hasTransport(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
+ }
+
+ public static class NetworkRequest.Builder {
+ ctor public NetworkRequest.Builder();
+ method public android.net.NetworkRequest.Builder addCapability(int);
+ method public android.net.NetworkRequest.Builder addTransportType(int);
+ method public android.net.NetworkRequest build();
+ method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
+ method public android.net.NetworkRequest.Builder removeCapability(int);
+ method public android.net.NetworkRequest.Builder removeTransportType(int);
+ method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
+ method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+ }
+
+ public final class Proxy {
+ ctor public Proxy();
+ method @Deprecated public static String getDefaultHost();
+ method @Deprecated public static int getDefaultPort();
+ method @Deprecated public static String getHost(android.content.Context);
+ method @Deprecated public static int getPort(android.content.Context);
+ field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+ field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
+ }
+
+ public class ProxyInfo implements android.os.Parcelable {
+ ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
+ method public static android.net.ProxyInfo buildDirectProxy(String, int);
+ method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
+ method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+ method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
+ method public int describeContents();
+ method public String[] getExclusionList();
+ method public String getHost();
+ method public android.net.Uri getPacFileUrl();
+ method public int getPort();
+ method public boolean isValid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
+ }
+
+ public final class RouteInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.IpPrefix getDestination();
+ method @Nullable public java.net.InetAddress getGateway();
+ method @Nullable public String getInterface();
+ method public boolean hasGateway();
+ method public boolean isDefaultRoute();
+ method public boolean matches(java.net.InetAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
+ }
+
+ public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+ method public final void close();
+ method public final void start(@IntRange(from=0xa, to=0xe10) int);
+ method public final void stop();
+ field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
+ field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0
+ field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
+ field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+ field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+ field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
+ field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+ field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
+ field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
+ field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2
+ }
+
+ public static class SocketKeepalive.Callback {
+ ctor public SocketKeepalive.Callback();
+ method public void onDataReceived();
+ method public void onError(int);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public interface TransportInfo {
+ }
+
+}
+
diff --git a/packages/Connectivity/framework/api/lint-baseline.txt b/packages/Connectivity/framework/api/lint-baseline.txt
new file mode 100644
index 0000000..2f4004a
--- /dev/null
+++ b/packages/Connectivity/framework/api/lint-baseline.txt
@@ -0,0 +1,4 @@
+// Baseline format: 1.0
+VisiblySynchronized: android.net.NetworkInfo#toString():
+ Internal locks must not be exposed (synchronizing on this or class is still
+ externally observable): method android.net.NetworkInfo.toString()
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
new file mode 100644
index 0000000..3af855e
--- /dev/null
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -0,0 +1,66 @@
+// Signature format: 2.0
+package android.net {
+
+ public final class ConnectivityFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ }
+
+ public class ConnectivityManager {
+ 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, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+ }
+
+ public final class NetworkAgentConfig implements android.os.Parcelable {
+ method @Nullable public String getSubscriberId();
+ }
+
+ public static final class NetworkAgentConfig.Builder {
+ method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ field public static final int TRANSPORT_TEST = 7; // 0x7
+ }
+
+ public final class Proxy {
+ method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
+ }
+
+ public final class TcpRepairWindow {
+ ctor public TcpRepairWindow(int, int, int, int, int, int);
+ field public final int maxWindow;
+ field public final int rcvWnd;
+ field public final int rcvWndScale;
+ field public final int rcvWup;
+ field public final int sndWl1;
+ field public final int sndWnd;
+ }
+
+ public final class TestNetworkInterface implements android.os.Parcelable {
+ ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
+ method public int describeContents();
+ method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
+ method @NonNull public String getInterfaceName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
+ }
+
+ public class TestNetworkManager {
+ method @NonNull public android.net.TestNetworkInterface createTapInterface();
+ method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
+ method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
+ method public void teardownTestNetwork(@NonNull android.net.Network);
+ field public static final String TEST_TAP_PREFIX = "testtap";
+ }
+
+ public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+ ctor public VpnTransportInfo(int);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+ field public final int type;
+ }
+
+}
+
diff --git a/packages/Connectivity/framework/api/module-lib-removed.txt b/packages/Connectivity/framework/api/module-lib-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/Connectivity/framework/api/module-lib-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/Connectivity/framework/api/removed.txt b/packages/Connectivity/framework/api/removed.txt
new file mode 100644
index 0000000..303a1e61
--- /dev/null
+++ b/packages/Connectivity/framework/api/removed.txt
@@ -0,0 +1,11 @@
+// Signature format: 2.0
+package android.net {
+
+ public class ConnectivityManager {
+ method @Deprecated public boolean requestRouteToHost(int, int);
+ method @Deprecated public int startUsingNetworkFeature(int, String);
+ method @Deprecated public int stopUsingNetworkFeature(int, String);
+ }
+
+}
+
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
new file mode 100644
index 0000000..41ebc57
--- /dev/null
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -0,0 +1,407 @@
+// Signature format: 2.0
+package android.net {
+
+ public class CaptivePortal implements android.os.Parcelable {
+ method public void logEvent(int, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
+ method public void useNetwork();
+ field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
+ field public static final int APP_RETURN_DISMISSED = 0; // 0x0
+ field public static final int APP_RETURN_UNWANTED = 1; // 0x1
+ field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
+ }
+
+ public final class CaptivePortalData implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getByteLimit();
+ method public long getExpiryTimeMillis();
+ method public long getRefreshTimeMillis();
+ method @Nullable public android.net.Uri getUserPortalUrl();
+ method public int getUserPortalUrlSource();
+ method @Nullable public String getVenueFriendlyName();
+ method @Nullable public android.net.Uri getVenueInfoUrl();
+ method public int getVenueInfoUrlSource();
+ method public boolean isCaptive();
+ method public boolean isSessionExtendable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
+ field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
+ }
+
+ public static class CaptivePortalData.Builder {
+ ctor public CaptivePortalData.Builder();
+ ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
+ method @NonNull public android.net.CaptivePortalData build();
+ method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
+ }
+
+ public class ConnectivityManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+ method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
+ method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void unregisterQosCallback(@NonNull android.net.QosCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+ field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
+ field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+ field public static final int TETHERING_USB = 1; // 0x1
+ field public static final int TETHERING_WIFI = 0; // 0x0
+ field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
+ field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field public static final int TYPE_NONE = -1; // 0xffffffff
+ field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
+ field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
+ }
+
+ public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
+ method public void onComplete();
+ }
+
+ @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
+ ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
+ method @Deprecated public void onTetheringFailed();
+ method @Deprecated public void onTetheringStarted();
+ }
+
+ @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
+ method @Deprecated public void onTetheringEntitlementResult(int);
+ }
+
+ @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
+ ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
+ method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ public final class InvalidPacketException extends java.lang.Exception {
+ ctor public InvalidPacketException(int);
+ method public int getError();
+ field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+ field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+ field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+ }
+
+ public final class IpConfiguration implements android.os.Parcelable {
+ ctor public IpConfiguration();
+ ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
+ method public int describeContents();
+ method @Nullable public android.net.ProxyInfo getHttpProxy();
+ method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
+ method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+ method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
+ method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+ method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
+ method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
+ method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
+ }
+
+ public enum IpConfiguration.IpAssignment {
+ enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
+ enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
+ enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
+ }
+
+ public enum IpConfiguration.ProxySettings {
+ enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
+ }
+
+ public final class IpPrefix implements android.os.Parcelable {
+ ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
+ ctor public IpPrefix(@NonNull String);
+ }
+
+ public class KeepalivePacketData {
+ ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
+ method @NonNull public java.net.InetAddress getDstAddress();
+ method public int getDstPort();
+ method @NonNull public byte[] getPacket();
+ method @NonNull public java.net.InetAddress getSrcAddress();
+ method public int getSrcPort();
+ }
+
+ public class LinkAddress implements android.os.Parcelable {
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
+ ctor public LinkAddress(@NonNull String);
+ ctor public LinkAddress(@NonNull String, int, int);
+ method public long getDeprecationTime();
+ method public long getExpirationTime();
+ method public boolean isGlobalPreferred();
+ method public boolean isIpv4();
+ method public boolean isIpv6();
+ method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
+ field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
+ }
+
+ public final class LinkProperties implements android.os.Parcelable {
+ ctor public LinkProperties(@Nullable android.net.LinkProperties);
+ ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
+ method public boolean addDnsServer(@NonNull java.net.InetAddress);
+ method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
+ method public boolean addPcscfServer(@NonNull java.net.InetAddress);
+ method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
+ method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
+ method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
+ method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
+ method @Nullable public android.net.Uri getCaptivePortalApiUrl();
+ method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
+ method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
+ method @Nullable public String getTcpBufferSizes();
+ method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
+ method public boolean hasGlobalIpv6Address();
+ method public boolean hasIpv4Address();
+ method public boolean hasIpv4DefaultRoute();
+ method public boolean hasIpv4DnsServer();
+ method public boolean hasIpv6DefaultRoute();
+ method public boolean hasIpv6DnsServer();
+ method public boolean isIpv4Provisioned();
+ method public boolean isIpv6Provisioned();
+ method public boolean isProvisioned();
+ method public boolean isReachable(@NonNull java.net.InetAddress);
+ method public boolean removeDnsServer(@NonNull java.net.InetAddress);
+ method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
+ method public boolean removeRoute(@NonNull android.net.RouteInfo);
+ method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
+ method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
+ method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
+ method public void setPrivateDnsServerName(@Nullable String);
+ method public void setTcpBufferSizes(@Nullable String);
+ method public void setUsePrivateDns(boolean);
+ method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
+ }
+
+ public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+ ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
+ }
+
+ public class Network implements android.os.Parcelable {
+ ctor public Network(@NonNull android.net.Network);
+ method public int getNetId();
+ method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
+ }
+
+ public abstract class NetworkAgent {
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ method @Nullable public android.net.Network getNetwork();
+ method public void markConnected();
+ method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
+ method public void onAutomaticReconnectDisabled();
+ method public void onNetworkUnwanted();
+ method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
+ method public void onQosCallbackUnregistered(int);
+ method public void onRemoveKeepalivePacketFilter(int);
+ method public void onSaveAcceptUnvalidated(boolean);
+ method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
+ method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
+ method public void onStopSocketKeepalive(int);
+ method public void onValidationStatus(int, @Nullable android.net.Uri);
+ method @NonNull public android.net.Network register();
+ method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
+ method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
+ method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
+ method public final void sendQosCallbackError(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
+ method public final void sendQosSessionLost(int, int);
+ method public final void sendSocketKeepaliveEvent(int, int);
+ method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
+ method public void unregister();
+ field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
+ field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
+ }
+
+ public final class NetworkAgentConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLegacyType();
+ method @NonNull public String getLegacyTypeName();
+ method public boolean isExplicitlySelected();
+ method public boolean isPartialConnectivityAcceptable();
+ method public boolean isUnvalidatedConnectivityAcceptable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
+ }
+
+ public static final class NetworkAgentConfig.Builder {
+ ctor public NetworkAgentConfig.Builder();
+ method @NonNull public android.net.NetworkAgentConfig build();
+ method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
+ method @NonNull public int[] getAdministratorUids();
+ method @Nullable public String getSsid();
+ method @NonNull public int[] getTransportTypes();
+ method public boolean isPrivateDnsBroken();
+ method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+ field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
+ field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
+ field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
+ field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
+ field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
+ }
+
+ public static final class NetworkCapabilities.Builder {
+ ctor public NetworkCapabilities.Builder();
+ ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
+ method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
+ method @NonNull public android.net.NetworkCapabilities build();
+ method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
+ method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
+ method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
+ method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
+ }
+
+ public class NetworkProvider {
+ ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
+ method public int getProviderId();
+ method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
+ method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
+ field public static final int ID_NONE = -1; // 0xffffffff
+ }
+
+ public class NetworkRequest implements android.os.Parcelable {
+ method @Nullable public String getRequestorPackageName();
+ method public int getRequestorUid();
+ }
+
+ public static class NetworkRequest.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+ }
+
+ public final class RouteInfo implements android.os.Parcelable {
+ ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
+ ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
+ method public int getMtu();
+ method public int getType();
+ field public static final int RTN_THROW = 9; // 0x9
+ field public static final int RTN_UNICAST = 1; // 0x1
+ field public static final int RTN_UNREACHABLE = 7; // 0x7
+ }
+
+ public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+ field public static final int SUCCESS = 0; // 0x0
+ }
+
+ public final class StaticIpConfiguration implements android.os.Parcelable {
+ ctor public StaticIpConfiguration();
+ ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ method public void addDnsServer(@NonNull java.net.InetAddress);
+ method public void clear();
+ method public int describeContents();
+ method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+ method @Nullable public String getDomains();
+ method @Nullable public java.net.InetAddress getGateway();
+ method @Nullable public android.net.LinkAddress getIpAddress();
+ method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
+ }
+
+ public static final class StaticIpConfiguration.Builder {
+ ctor public StaticIpConfiguration.Builder();
+ method @NonNull public android.net.StaticIpConfiguration build();
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
+ }
+
+ public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+ ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
+ field public final int ipTos;
+ field public final int ipTtl;
+ field public final int tcpAck;
+ field public final int tcpSeq;
+ field public final int tcpWindow;
+ field public final int tcpWindowScale;
+ }
+
+ public interface TransportInfo {
+ method public default boolean hasLocationSensitiveFields();
+ method @NonNull public default android.net.TransportInfo makeCopy(boolean);
+ }
+
+}
+
+package android.net.apf {
+
+ public final class ApfCapabilities implements android.os.Parcelable {
+ ctor public ApfCapabilities(int, int, int);
+ method public int describeContents();
+ method public static boolean getApfDrop8023Frames();
+ method @NonNull public static int[] getApfEtherTypeBlackList();
+ method public boolean hasDataAccess();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
+ field public final int apfPacketFormat;
+ field public final int apfVersionSupported;
+ field public final int maximumApfProgramSize;
+ }
+
+}
+
+package android.net.util {
+
+ public final class SocketUtils {
+ method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
+ method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
+ method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+ method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
+ }
+
+}
+
diff --git a/packages/Connectivity/framework/api/system-lint-baseline.txt b/packages/Connectivity/framework/api/system-lint-baseline.txt
new file mode 100644
index 0000000..9a97707
--- /dev/null
+++ b/packages/Connectivity/framework/api/system-lint-baseline.txt
@@ -0,0 +1 @@
+// Baseline format: 1.0
diff --git a/packages/Connectivity/framework/api/system-removed.txt b/packages/Connectivity/framework/api/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/Connectivity/framework/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index e7ab0a1..39ec2edc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -2245,31 +2245,6 @@
}
}
- /* TODO: These permissions checks don't belong in client-side code. Move them to
- * services.jar, possibly in com.android.server.net. */
-
- /** {@hide} */
- public static final void enforceChangePermission(Context context,
- String callingPkg, String callingAttributionTag) {
- int uid = Binder.getCallingUid();
- checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg,
- callingAttributionTag, true /* throwException */);
- }
-
- /**
- * Check if the package is a allowed to change the network state. This also accounts that such
- * an access happened.
- *
- * @return {@code true} iff the package is allowed to change the network state.
- */
- // TODO: Remove method and replace with direct call once R code is pushed to AOSP
- private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context,
- int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag,
- boolean throwException) {
- return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage,
- callingAttributionTag, throwException);
- }
-
/**
* Check if the package is a allowed to write settings. This also accounts that such an access
* happened.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index 4e3085f..b4a651c 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -16,6 +16,22 @@
package android.net;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+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_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+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_PARTIAL_CONNECTIVITY;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -30,6 +46,8 @@
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -154,8 +172,30 @@
* needed in terms of {@link NetworkCapabilities} features
*/
public static class Builder {
+ /**
+ * Capabilities that are currently compatible with VCN networks.
+ */
+ private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
+ NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_DUN,
+ NET_CAPABILITY_FOREGROUND,
+ NET_CAPABILITY_INTERNET,
+ NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_METERED,
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_NOT_ROAMING,
+ NET_CAPABILITY_NOT_SUSPENDED,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+ NET_CAPABILITY_TRUSTED,
+ NET_CAPABILITY_VALIDATED);
+
private final NetworkCapabilities mNetworkCapabilities;
+ // A boolean that represents the user modified NOT_VCN_MANAGED capability.
+ private boolean mModifiedNotVcnManaged = false;
+
/**
* Default constructor for Builder.
*/
@@ -177,6 +217,7 @@
// maybeMarkCapabilitiesRestricted() doesn't add back.
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
nc.maybeMarkCapabilitiesRestricted();
+ deduceNotVcnManagedCapability(nc);
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
}
@@ -193,6 +234,9 @@
*/
public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -204,6 +248,9 @@
*/
public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.removeCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -261,6 +308,9 @@
@NonNull
public Builder clearCapabilities() {
mNetworkCapabilities.clearAll();
+ // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
+ // should not be add back later.
+ mModifiedNotVcnManaged = true;
return this;
}
@@ -380,6 +430,25 @@
mNetworkCapabilities.setSignalStrength(signalStrength);
return this;
}
+
+ /**
+ * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
+ * and user intention, which includes:
+ * 1. For the requests that don't have anything besides
+ * {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
+ * allow the callers automatically utilize VCN networks if available.
+ * 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
+ * do not alter them to allow user fire request that suits their need.
+ *
+ * @hide
+ */
+ private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
+ if (mModifiedNotVcnManaged) return;
+ for (final int cap : nc.getCapabilities()) {
+ if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
+ }
+ nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ }
}
// implement the Parcelable interface
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index 9ccb04a..b5e8a61 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -91,7 +91,8 @@
* this socket will go directly to the underlying network, so its traffic will not be
* forwarded through the VPN.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
+ publicAlternatives = "Use {@link android.net.VpnService#protect} instead.")
public static native boolean protectFromVpn(FileDescriptor fd);
/**
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index 0242ba0..340141b 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 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.
diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 85e3fa3..43fffd7 100644
--- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -40,6 +40,8 @@
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
/**
* A class to encapsulate management of the "Smart Networking" capability of
@@ -73,6 +75,32 @@
private volatile int mMeteredMultipathPreference;
private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ // Mainline module can't use internal HandlerExecutor, so add an identical executor here.
+ private static class HandlerExecutor implements Executor {
+ @NonNull
+ private final Handler mHandler;
+
+ HandlerExecutor(@NonNull Handler handler) {
+ mHandler = handler;
+ }
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+ }
+
+ @VisibleForTesting
+ protected class ActiveDataSubscriptionIdChangedListener extends PhoneStateListener
+ implements PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ mActiveSubId = subId;
+ reevaluateInternal();
+ }
+ }
+
public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
}
@@ -93,14 +121,8 @@
}
};
- ctx.getSystemService(TelephonyManager.class).listen(
- new PhoneStateListener(handler.getLooper()) {
- @Override
- public void onActiveDataSubscriptionIdChanged(int subId) {
- mActiveSubId = subId;
- reevaluateInternal();
- }
- }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+ ctx.getSystemService(TelephonyManager.class).registerPhoneStateListener(
+ new HandlerExecutor(handler), new ActiveDataSubscriptionIdChangedListener());
updateAvoidBadWifi();
updateMeteredMultipathPreference();
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index 0346d74..513eba2 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -42,7 +42,7 @@
<string name="keyboard_layout_greek" msgid="7289253560162386040">"Greziarra"</string>
<string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrearra"</string>
<string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniera"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espainiera (Latinoamerika)"</string>
+ <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espainiarra (Latinoamerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letoniera"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persiarra"</string>
<string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijandarra"</string>
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index c9d8a81..139c8e5 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -162,6 +162,9 @@
if (mParameters.isFakeEncryptionFlag()) {
flags |= BackupAgent.FLAG_FAKE_CLIENT_SIDE_ENCRYPTION_ENABLED;
}
+ if (mParameters.isDeviceTransfer()) {
+ flags |= BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER;
+ }
return flags;
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 4b253c4..eafc614 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ignoreer kodewisselingverstekke"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktiveer kodewisseling"</string>
<string name="transcode_default" msgid="3784803084573509491">"Aanvaar dat programme moderne formate steun"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Wys kodewisselingkennisgewings"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Lopende dienste"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Sien en beheer dienste wat tans aktief is"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4982f82..547d0af 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"የትራንስኮዲንግ ነባሪዎችን ሻር"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ትራንስኮዲንግን ያንቁ"</string>
<string name="transcode_default" msgid="3784803084573509491">"መተግበሪያዎች ዘመናዊ ቅርጸቶችን እንደሚደግፉ አድርገው ይቁጠሩ"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ትራንስኮዲንግ ማሳወቂያዎችን አሳይ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"አሂድ አገልግሎቶች"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"በአሁኑጊዜ እየሄዱ ያሉ አገልግሎቶችን ተቆጣጠር እና እይ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"የWebView ትግበራ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 5eaefd0..c6a1d18f 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"إلغاء الإعدادات التلقائية لتحويل الترميز"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"تفعيل تحويل الترميز"</string>
<string name="transcode_default" msgid="3784803084573509491">"افتراض أن التطبيق يتوافق مع التنسيقات الحديثة"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"إظهار إشعارات تحويل الترميز"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"الخدمات قيد التشغيل"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"تطبيق WebView"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 571f7d0..e9deb46 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ট্ৰেন্সক’ডিং ডিফ’ল্ট অ’ভাৰৰাইড কৰক"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ট্ৰেন্সক’ডিং সক্ষম কৰক"</string>
<string name="transcode_default" msgid="3784803084573509491">"এপে আধুনিক ফৰ্মেট সমৰ্থন কৰে বুলি ধৰি লওক"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ট্ৰান্সক\'ডিঙৰ জাননী দেখুৱাওক"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"চলিত সেৱা"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"বৰ্তমান চলি থকা সেৱাসমূহ চাওক আৰু নিয়ন্ত্ৰণ কৰক"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ৱেবভিউ প্ৰয়োগ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 36a13f5..d04409c 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Yenidən kodlaşdırma defoltlarını əvəzləyin"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Yenidən kodlaşdırmanı aktiv edin"</string>
<string name="transcode_default" msgid="3784803084573509491">"Tətbiqlərin müasir formatları dəstəklədiyini qəbul edin"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Kod dəyişmə bildirişlərini göstərin"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"İşləyən xidmətlər"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Hazırda prosesdə olan xidmətləri görüntüləyin və onlara nəzarət edin"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView icrası"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index d7cc909..ecd70a2 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Zameni podrazumevana podešavanja transkodiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Podrazumevaj da aplikacije podržavaju moderne formate"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Prikazuj obaveštenja o transkodiranju"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Primena WebView-a"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 01201b3..6a3b961 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Перавызначыць стандартныя налады перакадзіравання"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Уключыць перакадзіраванне"</string>
<string name="transcode_default" msgid="3784803084573509491">"Лічыца, што праграмы падтрымліваюць сучасныя фарматы"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Паказваць апавяшчэнні пра перакадзіраванне"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Запушчаныя службы"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Прагляд запушчаных службаў i кіраванне iмi"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Рэалізацыя WebView"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 00f5e71..d2bf705 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Отмяна на стандартните настройки за прекодирането"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Активиране на прекодирането"</string>
<string name="transcode_default" msgid="3784803084573509491">"Предполагане, че приложенията поддържат съвременни формати"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Показване на известията за прекодиране"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Изпълнявани услуги"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Внедряване на WebView"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 43bb758..3ccf0e4 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ট্রান্সকোডিং ডিফল্ট সেটিংস ওভাররাইড করুন"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ট্রান্সকোডিং চালু করুন"</string>
<string name="transcode_default" msgid="3784803084573509491">"অ্যাপ মর্ডার্ন ফর্ম্যাটে কাজ করবে বলে ধরে নিন"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ট্রান্সকোডিং বিজ্ঞপ্তি দেখুন"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"এখন চলছে যে পরিষেবাগুলি"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ওয়েবভিউ প্রয়োগ"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index dacacfb..f01eef3 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Zaobiđi zadane postavke transkodiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Prikaži obavještenja o transkodiranju"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Postavljanje WebViewa"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 17482ed..7069999 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substitueix els valors predeterminats de la transcodificació"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activa la transcodificació"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assumeix que les aplicacions són compatibles amb formats moderns"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostra les notificacions de transcodificació"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serveis en execució"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualitza i controla els serveis en execució"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementació de WebView"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index ddd5c52..c677fef 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Přepsat výchozí nastavení překódování"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Povolit překódování"</string>
<string name="transcode_default" msgid="3784803084573509491">"Předpokládat, že aplikace podporují moderní formáty"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Zobrazit oznámení o překódování"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Spuštěné služby"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementace WebView"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 421ed74..84247a6 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Tilsidesæt standardindstillingerne for omkodning"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktivér omkodning"</string>
<string name="transcode_default" msgid="3784803084573509491">"Gå ud fra, at apps understøtter moderne formater"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Vis notifikationer for omkodning"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Kørende tjenester"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Vis og administrer kørende tjenester"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 7cb994c..4cc79d3 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Standardeinstellungen für Transcodierung überschreiben"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Transcodierung aktivieren"</string>
<string name="transcode_default" msgid="3784803084573509491">"Voraussetzen, dass Apps moderne Formate unterstützen"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Benachrichtigungen zur Transcodierung anzeigen"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive Dienste"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 7a73ccd..30705a1 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Παράκαμψη προεπιλογών διακωδικοποίησης"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ενεργοποίηση διακωδικοποίησης"</string>
<string name="transcode_default" msgid="3784803084573509491">"Να θεωρείται ότι οι εφαρμογές χρησιμοποιούν σύγχρονες μορφές"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Εμφάνιση ειδοποιήσεων διακωδικοποίησης"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Υπηρεσίες που εκτελούνται"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Προβολή και έλεγχος των εφαρμογών που εκτελούνται αυτή τη στιγμή"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Υλοποίηση WebView"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 6241953..b3d80ab 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 198fee4..ecf97ad 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 6241953..b3d80ab 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 6241953..b3d80ab 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 27cd8b3..c3a3f3f 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 5e5b39a..eb2a23b 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Anular los valores predeterminados de transcodificación"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar la transcodificación"</string>
<string name="transcode_default" msgid="3784803084573509491">"Suponer que las apps admiten formatos modernos"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificaciones de transcodificación"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"En ejecución"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar servicios actuales en ejecución"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8d79177..fe9984b 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar transcodificación"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que las aplicaciones admiten formatos modernos"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificaciones de transcodificación"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servicios en ejecución"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar los servicios en ejecución"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 18ee623..c70700d 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Alista transkodeerimise vaikeseaded"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Luba transkodeerimine"</string>
<string name="transcode_default" msgid="3784803084573509491">"Oleta, et rakendused toetavad kaasaegseid vorminguid"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Kuva transkodeerimise märguanded"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käitatud teenused"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Praegu käitatud teenuste vaatamine ja juhtimine"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView\' rakendamine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 71be593..09c964a 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ez erabili transkodetzearen balio lehenetsiak"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Gaitu transkodetzea"</string>
<string name="transcode_default" msgid="3784803084573509491">"Arduratu aplikazioek formatu modernoak onartzeaz"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Erakutsi transkodetze-jakinarazpenak"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 81a2cf8..22cd6ae 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ملغی کردن پیشفرضهای تراتبدیل"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"فعال کردن تراتبدیل"</string>
<string name="transcode_default" msgid="3784803084573509491">"فرض شود برنامهها از قالبهای مدرن پشتیبانی میکنند"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"نمایش اعلانهای تراتبدیل"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"سرویسهای در حال اجرا"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"مشاهده و کنترل سرویسهای در حال اجرای فعلی"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"اجرای وبنما"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 0703c45..22dde69 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ohita transkoodauksen oletukset"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Salli transkoodaus"</string>
<string name="transcode_default" msgid="3784803084573509491">"Oleta, että sovellukset tukevat nykyaikaisia formaatteja"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Näytä transkoodausilmoituksia"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Käynnissä olevat palvelut"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tarkastele ja hallitse käynnissä olevia palveluita."</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-käyttöönotto"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 5b8c938..d189f72 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Remplacer les valeurs par défaut de transcodage"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
<string name="transcode_default" msgid="3784803084573509491">"Présumer que les applications prennent en charge les formats modernes"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Afficher les notifications de transcodage"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index b025357..49d7faa 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ignorer les paramètres de transcodage par défaut"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
<string name="transcode_default" msgid="3784803084573509491">"Supposer que les applications sont compatibles avec les formats modernes"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Afficher les notifications de transcodage"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index d68595e..0922c3d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activar transcodificación"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que as aplicacións admiten formatos modernos"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificacións de transcodificación"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servizos en uso"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Comproba e controla os servizos actualmente en uso"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index e151ddb..10c5cc8 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ફૉર્મેટ બદલવાની પ્રક્રિયાના ડિફૉલ્ટ સેટિંગ ઓવરરાઇડ કરો"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
<string name="transcode_default" msgid="3784803084573509491">"ધારો કે ઍપ આધુનિક ફૉર્મેટ પર કામ કરે છે"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ફૉર્મેટ બદલવાની પ્રક્રિયાના નોટિફિકેશન બતાવો"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ચાલુ સેવાઓ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index beab7bd..ea25406 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ट्रांसकोडिंग की डिफ़ॉल्ट सेटिंग बदलें"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ट्रांसकोडिंग चालू करें"</string>
<string name="transcode_default" msgid="3784803084573509491">"मानकर चलें कि ऐप्लिकेशन, नए फ़ॉर्मैट के साथ काम करेंगे"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ट्रांसकोडिंग की सूचनाएं दिखाएं"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"चल रही सेवाएं"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"इस समय चल रही सेवाओं को देखें और नियंत्रित करें"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"वेबव्यू लागू करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 8989cc9..27a7a6e 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Nadjačaj zadane postavke konvertiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogući konvertiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Prikaži obavijesti o konvertiranju"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Pregledajte i kontrolirajte pokrenute usluge"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacija WebViewa"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 7c5a1a0..70a48b6 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Az átkódolás alapértelmezett beállításainak felülbírálása"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Átkódolás engedélyezése"</string>
<string name="transcode_default" msgid="3784803084573509491">"Annak feltételezése, hogy az alkalmazások támogatják a modern formátumokat"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Átkódolási értesítések megjelenítése"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Futó szolgáltatások"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"A jelenleg futó szolgáltatások megtekintése és vezérlése"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-megvalósítás"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 6684d35..c39e966 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Չեղարկել վերակոդավորման կանխադրված կարգավորումները"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Միացնել վերակոդավորումը"</string>
<string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Ցուցադրել անդրկոդավորման ծանուցումներ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 075444c..037c1b3 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ganti default transcoding"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktifkan transcoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Asumsikan aplikasi mendukung format modern"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Tampilkan notifikasi transcoding"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Layanan yang sedang berjalan"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Melihat dan mengontrol layanan yang sedang berjalan"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Penerapan WebView"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index b079f4d..3f87830 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Hnekkja sjálfgefinni umkóðun"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Kveikja á umkóðun"</string>
<string name="transcode_default" msgid="3784803084573509491">"Gera ráð fyrir að forrit styðji nútímasnið"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Sýna umkóðunartilkynningar"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Þjónustur í gangi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Skoða og stjórna þjónustum í gangi"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Innleiðing WebView"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index bf525c5..80ab57b 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Sostituisci impostazioni predefinite transcodifica"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Attiva transcodifica"</string>
<string name="transcode_default" msgid="3784803084573509491">"Presupponi che le app supportino i formati moderni"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostra notifiche relative alla transcodifica"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servizi in esecuzione"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizza e controlla i servizi attualmente in esecuzione"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementazione di WebView"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 9055e77..4355f31 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ביטול ברירות המחדל של המרת קידוד"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"הפעלת המרת קידוד"</string>
<string name="transcode_default" msgid="3784803084573509491">"הנחת העבודה היא שאפליקציות תומכות בפורמטים מודרניים"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"הצגת התראות לגבי המרת קידוד"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"שירותים פועלים"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"הצגת השירותים הפועלים כעת ושליטה בהם"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"יישום WebView"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 7fa0df9..ea4a683 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"デフォルトのコード変換をオーバーライド"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"コード変換を有効にする"</string>
<string name="transcode_default" msgid="3784803084573509491">"アプリによる最新形式のサポートを想定"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"コード変換に関する通知の表示"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"実行中のサービス"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"現在実行中のサービスを表示して制御する"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView の実装"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 7dd1eee..5798a46 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ტრანსკოდირების ნაგულისხმევების უგულებელყოფა"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ტრანსკოდირების ჩართვა"</string>
<string name="transcode_default" msgid="3784803084573509491">"დაშვება, რომ აპებს აქვთ თანამედროვე ფორმატების მხარდაჭერა"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ტრანსკოდირების შეტყობინებების ჩვენება"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"მიმდინარე სერვისები"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView რეალიზაცია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 59b1d63..5ce4e3a 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Қайта қодтаудың әдепкі параметрлерін қайта анықтау"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Қайта кодтауды қосу"</string>
<string name="transcode_default" msgid="3784803084573509491">"Қолданбалар қазіргі заманғы форматтарды қолдайды делік"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Қайта кодтау хабарландыруларын көрсету"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Қосылып тұрған қызметтер"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Қазір істеп тұрған қызметтерді көру және басқару"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView қызметі"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index b01839d..e6f2cb0 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"លុបពីលើលំនាំដើមនៃការបំប្លែងកូដ"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"បើកការបំប្លែងកូដ"</string>
<string name="transcode_default" msgid="3784803084573509491">"សន្មតថាកម្មវិធីអាចប្រើទម្រង់ទំនើបបាន"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"បង្ហាញការជូនដំណឹងអំពីការបំប្លែងកូដ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"សេវាកម្មកំពុងដំណើរការ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"មើល និងគ្រប់គ្រងសេវាកម្មកំពុងដំណើរការបច្ចុប្បន្ន"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ការអនុវត្ត WebView"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 217c917..561e6be 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -404,6 +404,8 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string>
+ <!-- no translation found for transcode_notification (5560515979793436168) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 0b8c71d..cd3b8b8 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"트랜스코딩 기본값 재정의"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"트랜스코딩 사용"</string>
<string name="transcode_default" msgid="3784803084573509491">"앱이 최신 형식을 지원하는 것으로 가정"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"트랜스코딩 알림 표시"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"실행 중인 서비스"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"현재 실행 중인 서비스 보기 및 제어"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 구현"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index cad00a3..1990353 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Демейки жүргүзүлгөн транскоддоону өзгөртүп коюу"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Транскоддоо жүргүзүүнү иштетүү"</string>
<string name="transcode_default" msgid="3784803084573509491">"Колдонмолордо заманбап форматтар колдоого алынат"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Транскоддоо билдирмелерин көрсөтүү"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView кызматы"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 5bd297e..4997ea1 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ຍົກເລີກຄ່າເລີ່ມຕົ້ນການປ່ຽນຮູບແບບລະຫັດ"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ເປີດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດ"</string>
<string name="transcode_default" msgid="3784803084573509491">"ສົມມຸດວ່າແອັບຮອງຮັບຮູບແບບສະໄໝໃໝ່"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ສະແດງການແຈ້ງເຕືອນການປ່ຽນຮູບແບບລະຫັດ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 8c7485f..ec3cb0d 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Perkodavimo numatytųjų nustatymų nepaisymas"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Perkodavimo įgalinimas"</string>
<string name="transcode_default" msgid="3784803084573509491">"Manoma, kad programos palaiko modernius formatus"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Rodyti perkodavimo pranešimus"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Vykdomos paslaugos"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"„WebView“ diegimas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index d8020c7..ff9f0a1 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ignorēt pārkodēšanas noklusējuma iestatījumus"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Iespējot pārkodēšanu"</string>
<string name="transcode_default" msgid="3784803084573509491">"Pieņemt, ka lietotnēs tiek atbalstīti moderni formāti"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Rādīt paziņojumus par pārkodēšanu"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktīvie pakalpojumi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ieviešana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index e4c8425..507f65c 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Отфрли стандардни вредности за транскодирање"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Овозможи транскодирање"</string>
<string name="transcode_default" msgid="3784803084573509491">"Претпостави дека апликациите поддржуваат модерни формати"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Прикажувај известувања за транскодирање"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Активни услуги"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Погледнете и контролирајте услуги што се моментално активни"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Воведување WebView"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 28422c9..8a09801 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ട്രാൻസ്കോഡ് ചെയ്യൽ ഡിഫോൾട്ടുകൾ അസാധുവാക്കുക"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ട്രാൻസ്കോഡ് ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="transcode_default" msgid="3784803084573509491">"ആപ്പുകൾ ആധുനിക ഫോർമാറ്റുകളെ പിന്തുണയ്ക്കുമെന്ന് കരുതുക"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ട്രാൻസ്കോഡ് ചെയ്യൽ അറിയിപ്പുകൾ കാണിക്കുക"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 0d78ea9..27ca8f5 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Хөрвүүлгийн өгөгдмөлийг дарах"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Хөрвүүлгийг идэвхжүүлэх"</string>
<string name="transcode_default" msgid="3784803084573509491">"Аппыг орчин үеийн форматыг дэмждэг гэж үздэг"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Хөрвүүлгийн мэдэгдэл харуулах"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Ажиллаж байгаа үйлчилгээнүүд"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Одоо ажиллаж байгаа үйлчилгээнүүдийг харах болон хянах"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView хэрэгжилт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index d27f705..b6c5460 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -404,6 +404,8 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिंग डीफॉल्ट ओव्हरराइड करा"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिंग सुरू करा"</string>
<string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string>
+ <!-- no translation found for transcode_notification (5560515979793436168) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index c5a2c62..53a4398 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Batalkan transpengekodan lalai"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Dayakan transpengekodan"</string>
<string name="transcode_default" msgid="3784803084573509491">"Mengambil alih sokongan apl format moden"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Tunjukkan pemberitahuan transpengekodan"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Perkhidmatan dijalankan"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Pelaksanaan WebView"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index ed34f7d..0fef5ab 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -307,7 +307,7 @@
<string name="adb_keys_warning_message" msgid="2968555274488101220">"သင် ယခင်က ခွင့်ပြုခဲ့သော ကွန်ပျူတာအားလုံးမှ ယူအက်စ်ဘီ အမှားစစ်ခွင့်ကို ရုတ်သိမ်းမည်လား ?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"တည်ဆောက်ပြုပြင်ရန်ဆက်တင်များကို အသုံးပြုခွင့်ပေးမည်လား?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"ဤဆက်တင်းများကို တည်ဆောက်ပြုပြင်ရာတွင် သုံးရန်အတွက်သာ ရည်ရွယ်သည်။ ၎င်းတို့သည် သင်၏စက်နှင့် အပလီကေးရှင်းများကို ရပ်စေခြင်း သို့ လုပ်ဆောင်ချက်မမှန်ကန်ခြင်းများ ဖြစ်ပေါ်စေနိုင်သည်။"</string>
- <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ဖြင့် အက်ပ်များကို အတည်ပြုစိစစ်ရန်"</string>
+ <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ဖြင့် အက်ပ်များစိစစ်ရန်"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADT မှတစ်ဆင့် ထည့်သွင်းသော အက်ပ်များ အန္တရာယ်ဖြစ်နိုင်ခြင်း ရှိမရှိ စစ်ဆေးသည်။"</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"အမည်မရှိသော (MAC လိပ်စာများသာပါသော) ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသပါမည်"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"ချိတ်ဆက်ထားသည့် ကိရိယာတွင် လက်မခံနိုင်လောက်အောင် ဆူညံ သို့မဟုတ် ထိန်းညှိမရနိုင်သော အသံပိုင်းပြဿနာ ရှိခဲ့လျှင် ဘလူးတုသ် ပကတိ အသံနှုန်းကို ပိတ်ပါ။"</string>
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"အမျိုးအစားပြောင်းခြင်း၏ မူရင်းဆက်တင်များကို အစားထိုးရန်"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"အမျိုးအစားပြောင်းခြင်းကို ဖွင့်ရန်"</string>
<string name="transcode_default" msgid="3784803084573509491">"ဤအက်ပ်များက ဖော်မက်အသစ်များကို ပံ့ပိုးသည်"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"အမျိုးအစားပြောင်းခြင်း အကြောင်းကြားချက်များကို ပြရန်"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"အလုပ်လုပ်နေသောဝန်ဆောင်မှုများ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"လက်ရှိ ဝန်ဆောင်မှုများကို ကြည့်ရှု ထိန်းသိမ်းသည်"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView အကောင်အထည်ဖော်မှု"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 5366e7e..0ca8d51 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Overstyr omkodingsstandarder"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Slå på omkoding"</string>
<string name="transcode_default" msgid="3784803084573509491">"Anta at apper støtter moderne formater"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Vis omkodingsvarsler"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive tjenester"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Se og kontrollér tjenester som kjører"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index cde7b80..75b4537 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -404,6 +404,8 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी पूर्वनिर्धारित सेटिङ परिवर्तन गर्नुहोस्"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string>
<string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string>
+ <!-- no translation found for transcode_notification (5560515979793436168) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index bb1402a..71d6acc 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Standaardwaarden voor transcodering overschrijven"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Transcodering inschakelen"</string>
<string name="transcode_default" msgid="3784803084573509491">"Aannemen dat apps moderne indelingen ondersteunen"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Transcoderingsmeldingen laten zien"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Actieve services"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Services die momenteel actief zijn, weergeven en beheren"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementatie"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 90fc8bc..1d6e34f 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ଟ୍ରାନ୍ସକୋଡିଂ ଡିଫଲ୍ଟଗୁଡ଼ିକୁ ଓଭରରାଇଡ୍ କରନ୍ତୁ"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ଟ୍ରାନ୍ସକୋଡିଂକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="transcode_default" msgid="3784803084573509491">"ଧରିନିଅନ୍ତୁ ଆପଗୁଡ଼ିକ ଆଧୁନିକ ଫର୍ମାଟଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ଟ୍ରାନ୍ସକୋଡିଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍ଭ୍ୟୁ ପ୍ରୟୋଗ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 4c20e19..9d91aae 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -404,6 +404,8 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਦੀਆਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
<string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string>
+ <!-- no translation found for transcode_notification (5560515979793436168) -->
+ <skip />
<string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 6d037d8..f48b05f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Zastąp ustawienia domyślne transkodowania"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Włącz transkodowanie"</string>
<string name="transcode_default" msgid="3784803084573509491">"Zakładaj, że aplikacje obsługują nowoczesne formaty"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Pokaż powiadomienia transkodowania"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Uruchomione usługi"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Wyświetl obecnie uruchomione usługi i nimi zarządzaj"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacja WebView"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3feed99..b9c9191 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index a886aa9..57e38c078 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substituir as predefinições da transcodificação"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ativar a transcodificação"</string>
<string name="transcode_default" msgid="3784803084573509491">"Assumir que as apps suportam formatos modernos"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços actualmente em execução"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação WebView"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3feed99..b9c9191 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
<string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 7fbe622..c2da73c 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Modificați setările prestabilite de transcodare"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Activați transcodarea"</string>
<string name="transcode_default" msgid="3784803084573509491">"Presupuneți că aplicațiile acceptă formatele moderne"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Vedeți notificările privind transcodarea"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Servicii în curs de funcționare"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Vedeți și controlați serviciile care funcționează în prezent"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementare WebView"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 1669df6..efcce75 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Переопределять настройки транскодирования по умолчанию"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Включить перекодирование"</string>
<string name="transcode_default" msgid="3784803084573509491">"Считать, что приложения поддерживают современные форматы кодирования"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Показывать уведомления о перекодировании"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Работающие службы"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Просмотр и управление работающими службами"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Сервис WebView"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 1fdd968..590e0e4 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ට්රාන්ස්කෝඩින් පෙරනිමි ප්රතික්ෂේප කරන්න"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ට්රාන්ස්කෝඩින් සබල කරන්න"</string>
<string name="transcode_default" msgid="3784803084573509491">"යෙදුම් නවීන ආකෘති සඳහා සහාය දක්වයි යැයි උපකල්පනය කරමු"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ට්රාන්ස්කෝඩින් දැනුම්දීම් පෙන්වන්න"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ධාවනය වන සේවා"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ක්රියාත්මක කිරීම"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 03b454e..c817ed0 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Prepísať predvolené nastavenia prekódovania"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Povoliť prekódovanie"</string>
<string name="transcode_default" msgid="3784803084573509491">"Prepdokladať, že aplikácie podporujú moderné formáty"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Zobraziť upozornenia prekódovania"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Spustené služby"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Zobrazovať a riadiť aktuálne spustené služby"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Implementácia WebView"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 73b4818..464b235 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Preglasi privzete nastavitve prekodiranja"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Omogoči prekodiranje"</string>
<string name="transcode_default" msgid="3784803084573509491">"Aplikacije naj bi podpirale sodobne oblike zapisov"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Prikaz obvestil o prekodiranju"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Zagnane storitve"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Preglejte in nadzorujte storitve, ki so trenutno zagnane"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Izvedba spletnega pogleda"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index a07bb2b..a2a63e1 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Anulo parazgjedhjet e transkodimit"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktivizo transkodimin"</string>
<string name="transcode_default" msgid="3784803084573509491">"Supozo se aplikacionet i mbështetin formatet moderne"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Shfaq njoftimet e transkodimit"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Shërbimet në ekzekutim"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Zbatimi i WebView"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 0faaf83..2119303 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Замени подразумевана подешавања транскодирања"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Омогући транскодирање"</string>
<string name="transcode_default" msgid="3784803084573509491">"Подразумевај да апликације подржавају модерне формате"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Приказуј обавештења о транскодирању"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Покренуте услуге"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Приказ и контрола тренутно покренутих услуга"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Примена WebView-а"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 87606d0..c7a2169 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Åsidosätta standardinställningar för omkodning"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Aktivera omkodning"</string>
<string name="transcode_default" msgid="3784803084573509491">"Anta att appar har stöd för moderna format"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Visa aviseringar för omkodning"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktiva tjänster"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Visa och styr aktiva tjänster"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index d479b0b..60014f4 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Batilisha chaguomsingi za kubadilisha miundo ya faili"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Ruhusu ubadilishaji wa miundo ya faili"</string>
<string name="transcode_default" msgid="3784803084573509491">"Chukulia kuwa programu zinatumia miundo ya kisasa"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Onyesha arifa za kubadilisha muundo wa faili"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Huduma zinazoendeshwa"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Onyesha na udhibiti huduma zinazoendeshwa kwa sasa"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Utekelezaji wa WebView"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 247889b..82cce12 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"இயல்புநிலை குறிமாற்றங்களை மீறிச் செயல்படு"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"குறிமாற்றத்தை இயக்கு"</string>
<string name="transcode_default" msgid="3784803084573509491">"ஆப்ஸ் மாடர்ன் வடிவங்களை ஆதரிக்கும்படி அமை"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"குறிமாற்ற அறிவிப்புகளைக் காட்டு"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"இயங்கும் சேவைகள்"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView செயல்படுத்தல்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index b5d584f..3b04eb4 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ట్రాన్స్కోడింగ్ ఆటోమేటిక్ సెట్టింగ్లను ఓవర్రైడ్ చేయండి"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ట్రాన్స్కోడింగ్ను ఎనేబుల్ చేయండి"</string>
<string name="transcode_default" msgid="3784803084573509491">"యాప్లు ఆధునిక ఫార్మాట్లకు సపోర్ట్ చేస్తాయని అనుకోండి"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ట్రాన్స్కోడింగ్ నోటిఫికేషన్లను చూపండి"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సేవలు"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సేవలను వీక్షించండి మరియు నియంత్రించండి"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index dc1514f..a970321 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ลบล้างค่าเริ่มต้นของการแปลง"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"เปิดใช้การแปลง"</string>
<string name="transcode_default" msgid="3784803084573509491">"ถือว่าแอปรองรับรูปแบบสมัยใหม่"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"แสดงการแจ้งเตือนการแปลง"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"บริการที่ทำงานอยู่"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ดูและควบคุมบริการที่ทำงานอยู่"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"การใช้งาน WebView"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 7c4ceec..bedd005 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"I-override ang mga default ng pagta-transcode"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"I-enable ang pagta-transcode"</string>
<string name="transcode_default" msgid="3784803084573509491">"Ipagpalagay na sinusuportahan ng mga app ang mga modernong format"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Ipakita ang mga notification sa pag-transcode"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Mga tumatakbong serbisyo"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Tingnan at kontrolin ang mga kasalukuyang tumatakbong serbisyo"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Pagpapatupad sa WebView"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 2b5dff15..2b2b44e 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Kod dönüştürme varsayılanlarını geçersiz kıl"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Kod dönüştürmeyi etkinleştir"</string>
<string name="transcode_default" msgid="3784803084573509491">"Uygulamaların modern biçimleri desteklediğini varsay"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Kod dönüştürme bildirimlerini göster"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Çalışan hizmetler"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Web Görünümü kullanımı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 6fff40d..9c5e2aa 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Замінити стандартні налаштування перекодування"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Увімкнути перекодування"</string>
<string name="transcode_default" msgid="3784803084573509491">"Вважати, що додатки підтримують сучасні формати"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Показувати сповіщення про перекодування"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Запущені сервіси"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Переглянути й налаштувати запущені сервіси"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Застосування WebView"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 055d9b8..ee06623 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"ٹرانسکوڈنگ ڈیفالٹس کو اوور رائیڈ کریں"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"ٹرانسکوڈنگ فعال کریں"</string>
<string name="transcode_default" msgid="3784803084573509491">"فرض کریں کہ ایپس جدید فارمیٹس کو سپورٹ کرتی ہیں"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"ٹرانسکوڈنگ اطلاعات دکھائیں"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"چل رہی سروسز"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView کا نفاذ"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index d897ba69..29c0f91 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Transkripsiya parametrlarini almashtirish"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Transkripsiyasini yoqish"</string>
<string name="transcode_default" msgid="3784803084573509491">"Ilovalarda zamonaviy kodlash formatlari ishlaydi deb hisoblash"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Transkripsiya bildirishnomalarini chiqarish"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Ishlab turgan ilovalar"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ta’minotchisi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index c6b7915..39beecd 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Ghi đè tùy chọn chuyển mã mặc định"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Bật tính năng chuyển mã"</string>
<string name="transcode_default" msgid="3784803084573509491">"Giả định rằng các ứng dụng hỗ trợ định dạng hiện đại"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Hiển thị thông báo chuyển mã"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Các dịch vụ đang chạy"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Xem và kiểm soát các dịch vụ đang chạy"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Triển khai WebView"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 05b27d1..010a4dc 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"覆盖转码默认设置"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"启用转码"</string>
<string name="transcode_default" msgid="3784803084573509491">"假设应用支持现代格式"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"显示转码通知"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"正在运行的服务"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看和控制当前正在运行的服务"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 实现"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 13398d7..1e06a91 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼功能"</string>
<string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新型格式"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"顯示轉碼通知"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"執行中的服務"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並控制目前正在執行中的服務"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index fead5e5..2c077e7 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼"</string>
<string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新格式"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"顯示轉碼通知"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"正在運作的服務"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並管理目前正在執行的服務"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 實作"</string>
@@ -434,9 +435,9 @@
<skip />
<string name="power_discharge_by_enhanced" msgid="563438403581662942">"根據你的使用情形,目前電量為 <xliff:g id="LEVEL">%2$s</xliff:g>,預估可持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"根據你的使用情形,預估可持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_discharge_by" msgid="4113180890060388350">"目前電量 <xliff:g id="LEVEL">%2$s</xliff:g>,預估還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_discharge_by" msgid="4113180890060388350">"目前電量 <xliff:g id="LEVEL">%2$s</xliff:g>,預估可用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"預估電力大約可使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_discharge_by_only_short" msgid="5883041507426914446">"還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_discharge_by_only_short" msgid="5883041507426914446">"可用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"電池電力可能於<xliff:g id="TIME">%1$s</xliff:g> 前耗盡"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 79b8946f1..87cf75b 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -404,6 +404,7 @@
<string name="transcode_user_control" msgid="6176368544817731314">"Khipha okuzenzakalelayo kokudlulisela ikhodi"</string>
<string name="transcode_enable_all" msgid="2411165920039166710">"Nika amandla ukudlulisela ikhodi"</string>
<string name="transcode_default" msgid="3784803084573509491">"Kuthathe njengokungathi izinhlelo zokusebenza zisekela amafomethi esimanje"</string>
+ <string name="transcode_notification" msgid="5560515979793436168">"Bonisa izaziso zokudlulisela ikhodi"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Amasevisi asebenzayo"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Buka futhi ulawule amasevisi asebenzayo okwamanje"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"Ukufakwa ke-WebView"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
index ecd4066..f9584a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
@@ -38,6 +38,7 @@
import android.os.UserManager;
import android.provider.ContactsContract.DisplayPhoto;
import android.provider.MediaStore;
+import android.util.EventLog;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
@@ -126,6 +127,14 @@
}
final Uri pictureUri = data != null && data.getData() != null
? data.getData() : mTakePictureUri;
+
+ // Check if the result is a content uri
+ if (!ContentResolver.SCHEME_CONTENT.equals(pictureUri.getScheme())) {
+ Log.e(TAG, "Invalid pictureUri scheme: " + pictureUri.getScheme());
+ EventLog.writeEvent(0x534e4554, "172939189", -1, pictureUri.getPath());
+ return false;
+ }
+
switch (requestCode) {
case REQUEST_CODE_CROP_PHOTO:
onPhotoCropped(pictureUri);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1ce738e..a0b9528 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -551,9 +551,6 @@
Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
GlobalSettingsProto.Development.FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS);
dumpSetting(s, p,
- Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
- GlobalSettingsProto.Development.ENABLE_SIZECOMPAT_FREEFORM);
- dumpSetting(s, p,
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
GlobalSettingsProto.Development.ENABLE_NON_RESIZABLE_MULTI_WINDOW);
p.end(developmentToken);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 303e5bb..4dc6d14 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -227,7 +227,6 @@
Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
Settings.Global.DEVELOPMENT_FORCE_RTL,
- Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7ced202..1393116 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -84,8 +84,6 @@
<uses-permission android:name="android.permission.READ_INPUT_STATE" />
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
- <!-- TODO(b/152310230): remove once APIs are confirmed to be sufficient -->
- <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
<uses-permission android:name="com.android.permission.USE_SYSTEM_DATA_LOADERS" />
<uses-permission android:name="android.permission.MOVE_PACKAGE" />
<uses-permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES" />
@@ -166,6 +164,7 @@
<uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
<uses-permission android:name="android.permission.MANAGE_SEARCH_UI" />
<uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
+ <uses-permission android:name="android.permission.MANAGE_UI_TRANSLATION" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.SET_TIME" />
@@ -400,6 +399,7 @@
<!-- Permission required for CTS to test sensor privacy behavior -->
<uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+ <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
<!-- Permission needed for CTS test - CallLogTest -->
<uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fbe58c5..b6d942a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -87,6 +87,7 @@
<uses-permission android:name="android.permission.MASTER_CLEAR" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+ <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
<!-- ActivityManager -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
@@ -337,6 +338,7 @@
<activity android:name=".screenshot.LongScreenshotActivity"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:process=":screenshot"
+ android:exported="false"
android:finishOnTaskLaunch="true" />
<activity android:name=".screenrecord.ScreenRecordDialog"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index bcd28a6..53f7e44 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -50,6 +50,4 @@
public abstract void onStateChanged(State state);
public abstract int getDetailY();
-
- public void setShowLabels(boolean show) {}
}
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
index ee86ae2..c0668db 100644
--- a/packages/SystemUI/res-product/values-az/strings.xml
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -38,8 +38,8 @@
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhd etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra iş profili silinəcək və bütün profil datası ləğv ediləcək."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
diff --git a/packages/SystemUI/res/drawable/control_no_favorites_background.xml b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
index d895dd0..2165b12 100644
--- a/packages/SystemUI/res/drawable/control_no_favorites_background.xml
+++ b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
@@ -26,12 +26,4 @@
<corners android:radius="@dimen/control_corner_radius" />
</shape>
</item>
- <item>
- <shape>
- <stroke
- android:width="1dp"
- android:color="#4DFFFFFF" />
- <corners android:radius="@dimen/control_corner_radius"/>
- </shape>
- </item>
</ripple>
diff --git a/packages/SystemUI/res/drawable/controls_dialog_bg.xml b/packages/SystemUI/res/drawable/controls_dialog_bg.xml
index cb4686dd..1ccb176 100644
--- a/packages/SystemUI/res/drawable/controls_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/controls_dialog_bg.xml
@@ -16,6 +16,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?android:attr/colorBackgroundFloating" />
+ <solid android:color="?android:attr/colorBackground" />
<corners android:radius="@dimen/notification_corner_radius" />
</shape>
diff --git a/packages/SystemUI/res/drawable/horizontal_ellipsis.xml b/packages/SystemUI/res/drawable/horizontal_ellipsis.xml
new file mode 100644
index 0000000..1800857
--- /dev/null
+++ b/packages/SystemUI/res/drawable/horizontal_ellipsis.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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorBackgroundFloating" >
+
+ <path
+ android:pathData="M6 10c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2zm12 0c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2zm-6 0c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2z"
+ android:fillColor="@android:color/white" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_tile_label_divider.xml b/packages/SystemUI/res/drawable/volume_drawer_bg.xml
similarity index 61%
copy from packages/SystemUI/res/layout/qs_tile_label_divider.xml
copy to packages/SystemUI/res/drawable/volume_drawer_bg.xml
index 150a5b8..f0e2292 100644
--- a/packages/SystemUI/res/layout/qs_tile_label_divider.xml
+++ b/packages/SystemUI/res/drawable/volume_drawer_bg.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2020 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,5 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<View />
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingMode="stack" >
+ <size android:width="@dimen/volume_ringer_drawer_item_size" />
+ <solid android:color="?android:attr/colorBackgroundFloating" />
+ <corners android:radius="@dimen/volume_ringer_drawer_item_size_half" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml b/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml
new file mode 100644
index 0000000..5e7cb12
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml
@@ -0,0 +1,24 @@
+<?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:paddingMode="stack" >
+ <size
+ android:height="@dimen/volume_ringer_drawer_item_size"
+ android:width="@dimen/volume_ringer_drawer_item_size" />
+ <solid android:color="?android:attr/colorAccent" />
+ <corners android:radius="@dimen/volume_ringer_drawer_item_size_half" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar.xml b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
new file mode 100644
index 0000000..b0e0ed5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
@@ -0,0 +1,56 @@
+<?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.
+ -->
+
+<!-- SeekBar drawable for volume rows. This contains a background layer (with a solid round rect,
+ and a bottom-aligned icon) and a progress layer (with an accent-colored round rect and icon)
+ that moves up and down with the progress value. -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingMode="stack" >
+ <item android:id="@android:id/background"
+ android:gravity="center_vertical|fill_horizontal">
+ <layer-list>
+ <item android:id="@+id/volume_seekbar_background_solid">
+ <shape>
+ <size android:height="@dimen/volume_dialog_panel_width" />
+ <solid android:color="?android:attr/colorBackgroundFloating" />
+ <corners android:radius="@dimen/volume_dialog_panel_width_half" />
+ </shape>
+ </item>
+ <item
+ android:id="@+id/volume_seekbar_background_icon"
+ android:gravity="center_vertical|left"
+ android:height="@dimen/rounded_slider_icon_size"
+ android:width="@dimen/rounded_slider_icon_size"
+ android:left="@dimen/rounded_slider_icon_inset">
+ <rotate
+ android:fromDegrees="-270"
+ android:toDegrees="-270">
+ <!-- A placeholder drawable is required here - it'll be replaced in code. -->
+ <com.android.systemui.util.AlphaTintDrawableWrapper
+ android:drawable="@drawable/ic_volume_media"
+ android:tint="?android:attr/colorAccent" />
+ </rotate>
+ </item>
+ </layer-list>
+ </item>
+ <item android:id="@android:id/progress"
+ android:gravity="center_vertical|fill_horizontal">
+ <com.android.systemui.util.RoundedCornerProgressDrawable
+ android:drawable="@drawable/volume_row_seekbar_progress"
+ />
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
new file mode 100644
index 0000000..ef20236
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
@@ -0,0 +1,44 @@
+<?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.
+ -->
+
+<!-- Progress drawable for volume row SeekBars. This is the accent-colored round rect that moves up
+ and down as the progress value changes. -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true">
+ <item android:id="@+id/volume_seekbar_progress_solid">
+ <shape>
+ <size android:height="@dimen/volume_dialog_panel_width" />
+ <solid android:color="?android:attr/colorAccent" />
+ <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
+ </shape>
+ </item>
+ <item
+ android:id="@+id/volume_seekbar_progress_icon"
+ android:gravity="center_vertical|right"
+ android:height="@dimen/rounded_slider_icon_size"
+ android:width="@dimen/rounded_slider_icon_size"
+ android:right="@dimen/rounded_slider_icon_inset">
+ <rotate
+ android:fromDegrees="-270"
+ android:toDegrees="-270">
+ <!-- A placeholder drawable is required here - it'll be replaced in code. -->
+ <com.android.systemui.util.AlphaTintDrawableWrapper
+ android:drawable="@drawable/ic_volume_media"
+ android:tint="?android:attr/colorBackgroundFloating" />
+ </rotate>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index c420117..237dc02 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -32,105 +32,124 @@
android:gravity="right"
android:layout_gravity="right"
android:background="@android:color/transparent"
- android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
- android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
- android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
+ android:paddingRight="@dimen/volume_dialog_stream_padding"
android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
android:clipToPadding="false">
- <FrameLayout
- android:id="@+id/ringer"
- android:layout_width="@dimen/volume_dialog_ringer_size"
- android:layout_height="@dimen/volume_dialog_ringer_size"
- android:layout_marginBottom="@dimen/volume_dialog_spacer"
- android:gravity="right"
- android:layout_gravity="right"
- android:translationZ="@dimen/volume_dialog_elevation"
- android:clipToPadding="false"
- android:background="@drawable/rounded_bg_full">
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/ringer_icon"
- style="@style/VolumeButtons"
- android:background="@drawable/rounded_ripple"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="fitCenter"
- android:padding="@dimen/volume_dialog_ringer_icon_padding"
- android:tint="@color/accent_tint_color_selector"
- android:layout_gravity="center"
- android:soundEffectsEnabled="false" />
-
- <include layout="@layout/volume_dnd_icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/volume_dialog_stream_padding"
- android:layout_marginTop="6dp"/>
- </FrameLayout>
-
+ <!--
+ Container for a) the ringer drawer and the caption button next to b) the volume rows.
+ -->
<LinearLayout
- android:id="@+id/main"
android:layout_width="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:layout_height="wrap_content"
- android:layout_marginTop="68dp"
- android:gravity="right"
- android:layout_gravity="right"
- android:orientation="vertical"
- android:translationZ="@dimen/volume_dialog_elevation"
+ android:orientation="horizontal"
android:clipChildren="false"
- android:clipToPadding="false"
- android:background="@drawable/rounded_bg_full" >
- <LinearLayout
- android:id="@+id/volume_dialog_rows"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
- android:gravity="center"
- android:orientation="horizontal"
- android:paddingRight="@dimen/volume_dialog_stream_padding"
- android:paddingLeft="@dimen/volume_dialog_stream_padding">
- <!-- volume rows added and removed here! :-) -->
- </LinearLayout>
- <FrameLayout
- android:id="@+id/settings_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/rounded_bg_bottom_background">
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/settings"
- android:src="@drawable/ic_tune_black_16dp"
- android:layout_width="@dimen/volume_dialog_tap_target_size"
- android:layout_height="@dimen/volume_dialog_tap_target_size"
- android:layout_gravity="center"
- android:contentDescription="@string/accessibility_volume_settings"
- android:background="@drawable/ripple_drawable_20dp"
- android:tint="?android:attr/textColorSecondary"
- android:soundEffectsEnabled="false" />
- </FrameLayout>
- </LinearLayout>
+ android:clipToPadding="false">
- <FrameLayout
- android:id="@+id/odi_captions"
- android:layout_width="@dimen/volume_dialog_caption_size"
- android:layout_height="@dimen/volume_dialog_caption_size"
- android:layout_marginRight="68dp"
- android:gravity="right"
- android:layout_gravity="right"
- android:clipToPadding="false"
- android:translationZ="@dimen/volume_dialog_elevation"
- android:background="@drawable/rounded_bg_full">
- <com.android.systemui.volume.CaptionsToggleImageButton
- android:id="@+id/odi_captions_icon"
- android:src="@drawable/ic_volume_odi_captions_disabled"
- style="@style/VolumeButtons"
- android:background="@drawable/rounded_ripple"
- android:layout_width="match_parent"
+ <!-- The ringer drawer and the caption button. -->
+ <FrameLayout
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:tint="@color/caption_tint_color_selector"
- android:layout_gravity="center"
- android:soundEffectsEnabled="false"
- sysui:optedOut="false"/>
- </FrameLayout>
+ android:paddingRight="@dimen/volume_dialog_stream_padding"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <include layout="@layout/volume_ringer_drawer"
+ android:layout_gravity="top|right"/>
+
+ <FrameLayout
+ android:id="@+id/odi_captions"
+ android:layout_width="@dimen/volume_dialog_caption_size"
+ android:layout_height="@dimen/volume_dialog_caption_size"
+ android:gravity="center"
+ android:layout_gravity="bottom|right"
+ android:layout_marginBottom="@dimen/volume_dialog_tap_target_size"
+ android:clipToPadding="false">
+
+ <com.android.systemui.volume.CaptionsToggleImageButton
+ android:id="@+id/odi_captions_icon"
+ android:src="@drawable/ic_volume_odi_captions_disabled"
+ style="@style/VolumeButtons"
+ android:background="@drawable/rounded_ripple"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:tint="@color/caption_tint_color_selector"
+ android:layout_gravity="center"
+ android:soundEffectsEnabled="false"
+ sysui:optedOut="false"/>
+
+ </FrameLayout>
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:visibility="gone"
+ android:id="@+id/ringer"
+ android:layout_width="@dimen/volume_dialog_ringer_size"
+ android:layout_height="@dimen/volume_dialog_ringer_size"
+ android:layout_marginBottom="@dimen/volume_dialog_spacer"
+ android:gravity="right"
+ android:layout_gravity="right"
+ android:translationZ="@dimen/volume_dialog_elevation"
+ android:clipToPadding="false"
+ android:background="@drawable/rounded_bg_full">
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/ringer_icon"
+ style="@style/VolumeButtons"
+ android:background="@drawable/rounded_ripple"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="fitCenter"
+ android:padding="@dimen/volume_dialog_ringer_icon_padding"
+ android:tint="@color/accent_tint_color_selector"
+ android:layout_gravity="center"
+ android:soundEffectsEnabled="false" />
+
+ <include layout="@layout/volume_dnd_icon"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/volume_dialog_stream_padding"
+ android:layout_marginTop="6dp"/>
+ </FrameLayout>
+
+ <LinearLayout
+ android:id="@+id/main"
+ android:layout_width="wrap_content"
+ android:minWidth="@dimen/volume_dialog_panel_width"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:layout_gravity="right"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ android:clipToPadding="false">
+ <LinearLayout
+ android:id="@+id/volume_dialog_rows"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="@dimen/volume_dialog_panel_width"
+ android:gravity="center"
+ android:orientation="horizontal">
+ <!-- volume rows added and removed here! :-) -->
+ </LinearLayout>
+ <FrameLayout
+ android:id="@+id/settings_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/settings"
+ android:src="@drawable/horizontal_ellipsis"
+ android:layout_width="@dimen/volume_dialog_tap_target_size"
+ android:layout_height="@dimen/volume_dialog_tap_target_size"
+ android:layout_gravity="center"
+ android:contentDescription="@string/accessibility_volume_settings"
+ android:background="@drawable/ripple_drawable_20dp"
+ android:tint="?android:attr/colorBackgroundFloating"
+ android:soundEffectsEnabled="false" />
+ </FrameLayout>
+ </LinearLayout>
+
+ </LinearLayout>
<ViewStub
android:id="@+id/odi_captions_tooltip_stub"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 0822947..93dd1a1 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -81,6 +81,22 @@
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_edit"
+ 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"
+ />
+
<com.android.systemui.statusbar.phone.MultiUserSwitch
android:id="@+id/multi_user_switch"
android:layout_width="@dimen/qs_footer_action_button_size"
diff --git a/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml b/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
index ee54f1d..c830773 100644
--- a/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
@@ -14,4 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<include layout="@layout/qs_paged_page" />
+<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_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 571cbbc..1ce87c1 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -20,7 +20,6 @@
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
- android:minHeight="48dp"
android:paddingTop="12dp">
<LinearLayout
android:id="@+id/label_group"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 4ca59f5..bbb6107 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -55,12 +55,14 @@
android:id="@+id/qs_frame"
android:layout="@layout/qs_panel"
android:layout_width="@dimen/qs_panel_width"
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:clipToPadding="false"
android:clipChildren="false"
systemui:viewType="com.android.systemui.plugins.qs.QS"
systemui:layout_constraintStart_toStartOf="parent"
systemui:layout_constraintEnd_toEndOf="parent"
+ systemui:layout_constraintTop_toTopOf="parent"
+ systemui:layout_constraintBottom_toBottomOf="parent"
/>
<androidx.constraintlayout.widget.Guideline
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 1810c19..6aac5a3 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -21,6 +21,8 @@
android:layout_height="wrap_content"
android:gravity="right"
android:layout_gravity="right"
+ android:paddingRight="@dimen/volume_dialog_stream_padding"
+ android:clipToPadding="false"
android:background="@android:color/transparent"
android:theme="@style/volume_dialog_theme">
@@ -34,13 +36,15 @@
android:layout_gravity="right"
android:background="@android:color/transparent"
android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
- android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
- android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
android:orientation="vertical"
- android:clipToPadding="false">
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <include layout="@layout/volume_ringer_drawer" />
<FrameLayout
+ android:visibility="gone"
android:id="@+id/ringer"
android:layout_width="@dimen/volume_dialog_ringer_size"
android:layout_height="@dimen/volume_dialog_ringer_size"
@@ -77,10 +81,8 @@
android:gravity="right"
android:layout_gravity="right"
android:orientation="vertical"
- android:translationZ="@dimen/volume_dialog_elevation"
android:clipChildren="false"
- android:clipToPadding="false"
- android:background="@drawable/rounded_bg_full" >
+ android:clipToPadding="false" >
<LinearLayout
android:id="@+id/volume_dialog_rows"
android:layout_width="wrap_content"
@@ -88,24 +90,22 @@
android:minWidth="@dimen/volume_dialog_panel_width"
android:gravity="center"
android:orientation="horizontal"
- android:paddingRight="@dimen/volume_dialog_stream_padding"
- android:paddingLeft="@dimen/volume_dialog_stream_padding">
+ android:layout_marginTop="@dimen/volume_row_slider_padding_start">
<!-- volume rows added and removed here! :-) -->
</LinearLayout>
<FrameLayout
android:id="@+id/settings_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/rounded_bg_bottom_background">
+ android:layout_height="wrap_content">
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/settings"
- android:src="@drawable/ic_tune_black_16dp"
+ android:src="@drawable/horizontal_ellipsis"
android:layout_width="@dimen/volume_dialog_tap_target_size"
android:layout_height="@dimen/volume_dialog_tap_target_size"
android:layout_gravity="center"
android:contentDescription="@string/accessibility_volume_settings"
android:background="@drawable/ripple_drawable_20dp"
- android:tint="?android:attr/textColorPrimary"
+ android:tint="?android:attr/colorBackgroundFloating"
android:soundEffectsEnabled="false" />
</FrameLayout>
</LinearLayout>
@@ -118,7 +118,6 @@
android:gravity="right"
android:layout_gravity="right"
android:clipToPadding="false"
- android:translationZ="@dimen/volume_dialog_elevation"
android:background="@drawable/rounded_bg_full">
<com.android.systemui.volume.CaptionsToggleImageButton
android:id="@+id/odi_captions_icon"
@@ -127,7 +126,7 @@
android:background="@drawable/rounded_ripple"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:tint="?android:attr/textColorPrimary"
+ android:tint="?android:attr/colorAccent"
android:layout_gravity="center"
android:soundEffectsEnabled="false"
sysui:optedOut="false"/>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index b9efc5b..fda59b5 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -20,11 +20,12 @@
android:layout_width="@dimen/volume_dialog_panel_width"
android:clipChildren="false"
android:clipToPadding="false"
+ android:translationZ="@dimen/volume_dialog_elevation"
android:theme="@style/volume_dialog_theme">
<LinearLayout
android:layout_height="wrap_content"
- android:layout_width="match_parent"
+ android:layout_width="@dimen/volume_dialog_panel_width"
android:gravity="center"
android:layout_gravity="center"
android:orientation="vertical" >
@@ -41,21 +42,23 @@
<FrameLayout
android:id="@+id/volume_row_slider_frame"
android:layout_width="match_parent"
- android:layout_marginTop="@dimen/volume_dialog_slider_margin_top"
- android:layout_marginBottom="@dimen/volume_dialog_slider_margin_bottom"
- android:layoutDirection="rtl"
- android:layout_height="@dimen/volume_dialog_slider_height">
+ android:layout_height="@dimen/volume_row_slider_height">
+ <include layout="@layout/volume_dnd_icon"/>
<SeekBar
android:id="@+id/volume_row_slider"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp"
+ android:paddingStart="0dp"
+ android:paddingEnd="0dp"
android:clickable="true"
- android:layout_width="@dimen/volume_dialog_slider_height"
+ android:layout_width="@dimen/volume_row_slider_height"
android:layout_height="match_parent"
- android:layoutDirection="rtl"
android:layout_gravity="center"
- android:rotation="90" />
+ android:rotation="270" />
</FrameLayout>
<com.android.keyguard.AlphaOptimizedImageButton
+ android:visibility="gone"
android:id="@+id/volume_row_icon"
style="@style/VolumeButtons"
android:layout_width="@dimen/volume_dialog_tap_target_size"
@@ -66,6 +69,4 @@
android:soundEffectsEnabled="false" />
</LinearLayout>
- <include layout="@layout/volume_dnd_icon"/>
-
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
new file mode 100644
index 0000000..d6e1782
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
@@ -0,0 +1,126 @@
+<?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.
+-->
+
+<!-- Contains the active ringer icon and a hidden drawer containing all three ringer options. -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <!-- Drawer view, invisible by default. -->
+ <FrameLayout
+ android:id="@+id/volume_drawer_container"
+ android:alpha="0.0"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/volume_drawer_bg"
+ android:orientation="vertical">
+
+ <!-- View that is animated to a tapped ringer selection, so it appears selected. -->
+ <FrameLayout
+ android:id="@+id/volume_drawer_selection_background"
+ android:alpha="0.0"
+ android:layout_width="@dimen/volume_ringer_drawer_item_size"
+ android:layout_height="@dimen/volume_ringer_drawer_item_size"
+ android:layout_gravity="bottom|right"
+ android:background="@drawable/volume_drawer_selection_bg" />
+
+ <LinearLayout
+ android:id="@+id/volume_drawer_options"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/volume_drawer_vibrate"
+ android:layout_width="@dimen/volume_ringer_drawer_item_size"
+ android:layout_height="@dimen/volume_ringer_drawer_item_size"
+ android:description="@string/volume_ringer_hint_vibrate"
+ android:gravity="center">
+
+ <ImageView
+ android:id="@+id/volume_drawer_vibrate_icon"
+ android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_gravity="center"
+ android:tint="?android:attr/colorAccent"
+ android:src="@drawable/ic_volume_ringer_vibrate" />
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/volume_drawer_mute"
+ android:layout_width="@dimen/volume_ringer_drawer_item_size"
+ android:layout_height="@dimen/volume_ringer_drawer_item_size"
+ android:description="@string/volume_ringer_hint_mute"
+ android:gravity="center">
+
+ <ImageView
+ android:id="@+id/volume_drawer_mute_icon"
+ android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_gravity="center"
+ android:tint="?android:attr/colorAccent"
+ android:src="@drawable/ic_volume_ringer_mute" />
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/volume_drawer_normal"
+ android:layout_width="@dimen/volume_ringer_drawer_item_size"
+ android:layout_height="@dimen/volume_ringer_drawer_item_size"
+ android:description="@string/volume_ringer_hint_unmute"
+ android:gravity="center">
+
+ <ImageView
+ android:id="@+id/volume_drawer_normal_icon"
+ android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_gravity="center"
+ android:tint="?android:attr/colorAccent"
+ android:src="@drawable/ic_volume_ringer" />
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <!-- The current ringer selection. When the drawer is opened, this animates to the corresponding
+ position in the drawer. When the drawer is closed, it animates back. -->
+ <FrameLayout
+ android:id="@+id/volume_new_ringer_active_icon_container"
+ android:layout_width="@dimen/volume_ringer_drawer_item_size"
+ android:layout_height="@dimen/volume_ringer_drawer_item_size"
+ android:layout_gravity="bottom|right"
+ android:description="@string/volume_ringer_change"
+ android:background="@drawable/volume_drawer_selection_bg">
+
+ <ImageView
+ android:id="@+id/volume_new_ringer_active_icon"
+ android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+ android:layout_gravity="center"
+ android:tint="?android:attr/colorBackgroundFloating"
+ android:src="@drawable/ic_volume_media" />
+
+ </FrameLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 68c7467..c3a62b0 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot sonsopkoms"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Verminder helderheid"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is gedeaktiveer"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is geaktiveer"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Hierdie toestel behoort aan <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swiep vanaf ikoon vir foon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swiep vanaf ikoon vir stembystand"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swiep vanaf ikoon vir kamera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om op vibreer te stel."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om te demp."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"demp"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ontdemp"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreer"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Voeg by"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Voorgestel deur <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontroles opgedateer"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Toestel is gesluit"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN bevat letters of simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifieer <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Verkeerde PIN"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7618af8..0c0487d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ጸሐይ እስክትወጣ ድረስ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ላይ ይበራል"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"እስከ <xliff:g id="TIME">%s</xliff:g> ድረስ"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ብሩህነትን ይቀንሱ"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ኤንኤፍሲ"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"ኤንኤፍሲ ተሰናክሏል"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"ኤንኤፍሲ ነቅቷል"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCን ለመጠቀም ይክፈቱ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ይህ መሣሪያ የድርጅትዎ ነው"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ይህ መሳሪያ ንብረትነቱ የ<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ነው"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ለስልክ ከአዶ ላይ ጠረግ ያድርጉ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ለድምጽ ረዳት ከአዶ ጠረግ ያድርጉ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ለካሜራ ከአዶ ላይ ጠረግ ያድርጉ"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ።"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ።"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ድምጸ-ከል አድርግ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ድምጸ-ከልን አንሳ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ንዘር"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"መሣሪያ ተቆልፏል"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ፒን ፊደሎችን ወይም ምልክቶችን ይይዛል"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> አረጋግጥ"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"የተሳሳተ ፒን"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 67622c7..ae8df90 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -420,7 +420,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"حتى شروق الشمس"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"تفعيل الوضع في <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"حتى <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"تقليل السطوع"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"تم إيقاف الاتصال القريب المدى"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"تم تفعيل الاتصال القريب المدى"</string>
@@ -454,6 +455,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"افتح قفل الشاشة لاستخدام تقنية NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"هذا الجهاز يخص مؤسستك."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"هذا الجهاز يخص <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"يمكنك التمرير سريعًا من الرمز لتشغيل الهاتف"</string>
<string name="voice_hint" msgid="7476017460191291417">"يمكنك التمرير سريعًا من الرمز لتشغيل المساعد الصوتي"</string>
<string name="camera_hint" msgid="4519495795000658637">"يمكنك التمرير سريعًا من الرمز لتشغيل الكاميرا"</string>
@@ -637,6 +640,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. انقر للتعيين على الاهتزاز."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. انقر لكتم الصوت."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"كتم الصوت"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"إعادة الصوت"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"اهتزاز"</string>
@@ -1062,6 +1067,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"الجهاز مُقفل."</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"يشتمل رقم التعريف الشخصي على أحرف أو رموز."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"إثبات ملكية <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"رقم تعريف شخصي خاطئ"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b1b28ad..1f92570 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূৰ্যোদয়লৈকে"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ত অন কৰক"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পৰ্যন্ত"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"উজ্জ্বলতা কমাওক"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC নিষ্ক্ৰিয় হৈ আছে"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম হৈ আছে"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ৰ"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ফ\'নৰ বাবে আইকনৰপৰা ছোৱাইপ কৰক"</string>
<string name="voice_hint" msgid="7476017460191291417">"কণ্ঠধ্বনিৰে সহায়ৰ বাবে আইকনৰ পৰা ছোৱাইপ কৰক"</string>
<string name="camera_hint" msgid="4519495795000658637">"কেমেৰা খুলিবলৈ আইকনৰপৰা ছোৱাইপ কৰক"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট কৰিবলৈ টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। কম্পন অৱস্থাত ছেট কৰিবলৈ টিপক।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট কৰিবলৈ টিপক।"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট কৰক"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট কৰক"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"কম্পন কৰক"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইচ লক হৈ আছে"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিনত বৰ্ণ অথবা প্ৰতীকসমূহ থাকে"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> সত্যাপন কৰক"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ভুল পিন"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index fed444b..e813a90 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Şəfəq vaxtına qədər"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bu vaxt aktiv olur: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bu vaxtadək: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Parlaqlığı Azaldın"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC deaktiv edilib"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC aktiv edilib"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> təşkilatına məxsusdur"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Telefon üçün ikonadan sürüşdürün"</string>
<string name="voice_hint" msgid="7476017460191291417">"Səs yardımçısı üçün ikonadan sürüşdürün"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kamera üçün ikonadan sürüşdürün"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Səssiz etmək üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Vibrasiyanı ayarlamaq üçün klikləyin."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Səssiz etmək üçün klikləyin."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"susdurun"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"səssiz rejimdən çıxarın"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrasiya"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Əlavə edin"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tərəfindən təklif edilib"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Nizamlayıcılar güncəlləndi"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilidlənib"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN hərflər və ya simvollar ehtiva edir"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Yanlış PIN"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ded8fa5..27d4b18 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanji osvetljenost"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Prevucite od ikone za telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Prevucite od ikone za glasovnu pomoć"</string>
<string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone za kameru"</string>
@@ -628,6 +631,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste podesili na vibraciju."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibracija"</string>
@@ -1044,6 +1049,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifikujte: <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 18756f8..ab1cc69 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -416,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Да ўсходу сонца"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Уключана ў <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Да <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Паменшыць яркасць"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC адключаны"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC уключаны"</string>
@@ -450,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Разблакіруйце, каб выкарыстоўваць NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Гэта прылада належыць вашай арганізацыі"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Гэта прылада належыць арганізацыі \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Тэлефон: правядзіце пальцам ад значка"</string>
<string name="voice_hint" msgid="7476017460191291417">"Галасавая дапамога: правядзіце пальцам ад значка"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камера: правядзіце пальцам ад значка"</string>
@@ -631,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дакраніцеся, каб уключыць вібрацыю."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дакраніцеся, каб адключыць гук"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"выключыць гук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"уключыць гук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вібрыраваць"</string>
@@ -1050,6 +1055,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Прылада блакіравана"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код складаецца з літар або знакаў"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Спраўдзіце прыладу \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Няправільны PIN-код"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e1efd3b..6716e15 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрев"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ще се включи в <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Намаляване на яркостта"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"КБП е деактивирана"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"КБП е активирана"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отключете, за да използвате NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Това устройство принадлежи на организацията ви"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Това устройство принадлежи на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Плъзнете с пръст от иконата, за да използвате телефона"</string>
<string name="voice_hint" msgid="7476017460191291417">"Прекарайте пръст от иконата, за да получите гласова помощ"</string>
<string name="camera_hint" msgid="4519495795000658637">"Плъзнете с пръст от иконата, за да включите камерата"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Докоснете, за да заглушите звука. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Докоснете, за да зададете вибриране."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Докоснете, за да заглушите звука."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"спиране"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"пускане"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибриране"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"У-вото е заключено"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН кодът съдържа букви или символи"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Потвърждаване на <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Грешен ПИН код"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 12f5345..ee639d6 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"স্ক্রিনশট স্ক্রল করুন"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্রিনশট বাতিল করুন"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্রিনশটের প্রিভিউ"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"স্ক্রিনশটের একদম উপরের দিকে"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"স্ক্রিনশটের একদম নিচের দিকে"</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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূর্যোদয় পর্যন্ত"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-এ চালু হবে"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পর্যন্ত"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"উজ্জ্বলতা কমান"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC অক্ষম করা আছে"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম করা আছে"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যবহার করতে আনলক করুন"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইসটি <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-এর"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ফোনের জন্য আইকন থেকে সোয়াইপ করুন"</string>
<string name="voice_hint" msgid="7476017460191291417">"ভয়েস সহায়তার জন্য আইকন থেকে সোয়াইপ করুন"</string>
<string name="camera_hint" msgid="4519495795000658637">"ক্যামেরার জন্য আইকন থেকে সোয়াইপ করুন"</string>
@@ -546,8 +547,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ভাইব্রেট করতে ট্যাপ করুন।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট করতে ট্যাপ করুন।"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট করুন"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট করুন"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ভাইব্রেট করান"</string>
@@ -1041,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইস লক করা আছে"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিন-এ অক্ষর বা চিহ্ন রয়েছে"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> যাচাই করুন"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ভুল পিন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 7463233..01a55d3 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svitanja"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanji osvjetljenje"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Prevucite preko ikone da otvorite telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Prevucite preko ikone za glasovnu pomoć"</string>
<string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone da otvorite kameru"</string>
@@ -628,6 +631,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da isključite zvuk. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da postavite vibraciju."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da isključite zvuk."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1044,6 +1049,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 524bb62..5d8ccbc 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fins a l\'alba"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activat a les <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fins a les <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducció de la brillantor"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"L\'NFC està desactivada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"L\'NFC està activada"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Aquest dispositiu pertany a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Llisca des de la icona per obrir el telèfon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Llisca des de la icona per obrir l\'assistent de veu"</string>
<string name="camera_hint" msgid="4519495795000658637">"Llisca des de la icona per obrir la càmera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca per activar la vibració."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca per silenciar."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"deixar de silenciar"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Afegeix"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggerit per <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"S\'han actualitzat els controls"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispositiu bloquejat"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN conté lletres o símbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecte"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 47a673d..024b836 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -416,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svítání"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapnout v <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Snížit jas"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
@@ -450,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zařízení patří organizaci <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Telefon otevřete přejetím prstem od ikony"</string>
<string name="voice_hint" msgid="7476017460191291417">"Hlasovou asistenci otevřete přejetím prstem od ikony"</string>
<string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otevřete přejetím prstem od ikony"</string>
@@ -631,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnete zvuk. Služby přístupnosti mohou být ztlumeny."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrace."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnout zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnout zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrovat"</string>
@@ -1050,6 +1055,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Přidat"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Návrh z aplikace <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládací prvky aktualizovány"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Zařízení uzamčeno"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kód PIN obsahuje písmena nebo symboly"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Ověření zařízení <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Chybný PIN"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index e12b91c..b1a7a5a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Indtil solopgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Tænd kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Indtil kl. <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducer lysstyrken"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er deaktiveret"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er aktiveret"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enhed tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Stryg fra telefonikonet"</string>
<string name="voice_hint" msgid="7476017460191291417">"Stryg fra mikrofonikonet"</string>
<string name="camera_hint" msgid="4519495795000658637">"Stryg fra kameraikonet"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryk for at aktivere vibration."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryk for at slå lyden fra."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"slå lyden fra"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå lyden til"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Tilføj"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Foreslået af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Betjeningselementerne er opdateret"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Enheden er låst"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden indeholder bogstaver eller symboler"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Bekræft <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Forkert pinkode"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 6a69ed2..88dd62d 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"Screenshot scrollen"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot schließen"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshotvorschau"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"Oberer Rand"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Unterer Rand"</string>
<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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Bis Sonnenaufgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"An um <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bis <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Helligkeit verringern"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ist deaktiviert"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ist aktiviert"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Dieses Gerät gehört <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Zum Öffnen des Telefons vom Symbol wegwischen"</string>
<string name="voice_hint" msgid="7476017460191291417">"Zum Öffnen des Sprachassistenten vom Symbol wegwischen"</string>
<string name="camera_hint" msgid="4519495795000658637">"Zum Öffnen der Kamera vom Symbol wegwischen"</string>
@@ -546,8 +547,7 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Deine Organisation hat ein Zertifikat einer Zertifizierungsstelle in deinem Arbeitsprofil installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Auf dem Gerät ist das Zertifikat einer Zertifizierungsstelle installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit wird der Netzwerkverkehr auf deinem Gerät überwacht."</string>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit werden die Zugriffe in deinem Arbeitsprofil erfasst, jedoch nicht in deinem privaten Profil."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Du bist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden. Die App kann deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Du bist mit <xliff:g id="VPN_APP_0">%1$s</xliff:g> und <xliff:g id="VPN_APP_1">%2$s</xliff:g> verbunden. Die Apps können deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Dein Arbeitsprofil ist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden, die deine Netzwerkaktivitäten wie E-Mails, Apps und Websites überwachen kann."</string>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Zum Aktivieren der Vibration tippen."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Zum Stummschalten tippen."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stummschalten"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"Stummschaltung aufheben"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrieren"</string>
@@ -1041,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Hinzufügen"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Vorgeschlagen von <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Gerätekarten aktualisiert"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Gerät gesperrt"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Die PIN enthält Buchstaben oder Symbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> bestätigen"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Falsche PIN"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 5bed0e5..2133025 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Μέχρι την ανατολή"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ενεργοποίηση στις <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Έως <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Μείωση φωτεινότητας"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Το NFC είναι απενεργοποιημένο"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Το NFC είναι ενεργοποιημένο"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ξεκλείδωμα για χρήση του NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Αυτή η συσκευή ανήκει στον οργανισμό σας."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Αυτή η συσκευή ανήκει στον οργανισμό <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Σύρετε προς τα έξω για τηλέφωνο"</string>
<string name="voice_hint" msgid="7476017460191291417">"Σύρετε προς τα έξω για voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Σύρετε προς τα έξω για κάμερα"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Πατήστε για να ενεργοποιήσετε τη δόνηση."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Πατήστε για σίγαση."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"σίγαση"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"κατάργηση σίγασης"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"δόνηση"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Η συσκευή κλειδώθηκε"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Το PIN περιέχει γράμματα ή σύμβολα"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Επαλήθευση <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Λάθος PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 5df29337..403fdee 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 46c09f6..a665fb1 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organization"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e1ad516..c97194f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir el brillo"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"La tecnología NFC está inhabilitada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"La tecnología NFC está habilitada"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Desliza el dedo para desbloquear el teléfono."</string>
<string name="voice_hint" msgid="7476017460191291417">"Desliza el dedo desde el ícono para abrir asistente de voz."</string>
<string name="camera_hint" msgid="4519495795000658637">"Desliza el dedo para acceder a la cámara."</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Presiona para establecer el modo vibración."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Presiona para silenciar."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Agregar"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispos. bloqueado"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecto"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c4b8b24..4c5ef0b 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A las <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta las <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir brillo"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"El NFC está desactivado"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"El NFC está activado"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Desliza desde el icono para abrir el teléfono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Desliza desde el icono para abrir asistente de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Desliza desde el icono para abrir la cámara"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para activar la vibración."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Añadir"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloqueado"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecto"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 5402b61..65c5930 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuni päikesetõusuni"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Sisse kell <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuni <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Ereduse vähendamine"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on keelatud"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on lubatud"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Selle seadme omanik on <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Telefoni kasutamiseks pühkige ikoonilt eemale"</string>
<string name="voice_hint" msgid="7476017460191291417">"Häälabi kasutamiseks pühkige ikoonilt eemale"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kaamera kasutamiseks pühkige ikoonilt eemale"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Puudutage vibreerimise määramiseks."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Puudutage vaigistamiseks."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vaigistamine"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vaigistuse tühistamine"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreerimine"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Lisa"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Soovitas <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Juhtelemente värskendati"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Seade on lukustatud"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-kood sisaldab tähti või sümboleid"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Kinnitage <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Vale PIN-kood"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 510e7f9..9cebde1 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Egunsentira arte"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Desaktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Murriztu distira"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Desgaituta dago NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Gaituta dago NFC"</string>
@@ -443,9 +444,11 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Irekitzeko, ukitu berriro"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasatu hatza gora irekitzeko"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Berriro saiatzeko, pasatu hatza gora"</string>
- <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokeatu NFC erabiltzeko"</string>
+ <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFC erabiltzeko"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Gailu hau <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> erakundearena da"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Pasatu hatza ikonotik, telefonoa irekitzeko"</string>
<string name="voice_hint" msgid="7476017460191291417">"Pasatu hatza ikonotik, ahots-laguntza irekitzeko"</string>
<string name="camera_hint" msgid="4519495795000658637">"Pasatu hatza ikonotik, kamera irekitzeko"</string>
@@ -461,8 +464,8 @@
<string name="keyguard_indication_charging_time_fast" msgid="7895986003578341126">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bizkor kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte)"</string>
<string name="keyguard_indication_charging_time_slowly" msgid="245442950133408398">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mantso kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte)"</string>
<string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
- <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Aldatu erabiltzailez. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita duena."</string>
- <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Uneko erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+ <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Aldatu erabiltzailea. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita daukana."</string>
+ <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Erakutsi profila"</string>
<string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzailea"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string>
@@ -478,7 +481,7 @@
<string name="guest_notification_text" msgid="4202692942089571351">"Aplikazioak eta datuak ezabatzeko, kendu gonbidatua"</string>
<string name="guest_notification_remove_action" msgid="4153019027696868099">"KENDU GONBIDATUA"</string>
<string name="user_logout_notification_title" msgid="3644848998053832589">"Amaitu erabiltzailearen saioa"</string>
- <string name="user_logout_notification_text" msgid="7441286737342997991">"Amaitu uneko erabiltzailearen saioa"</string>
+ <string name="user_logout_notification_text" msgid="7441286737342997991">"Amaitu erabiltzailearen saioa"</string>
<string name="user_logout_notification_action" msgid="7974458760719361881">"AMAITU ERABILTZAILEAREN SAIOA"</string>
<string name="user_add_user_title" msgid="4172327541504825032">"Beste erabiltzaile bat gehitu?"</string>
<string name="user_add_user_message_short" msgid="2599370307878014791">"Erabiltzaile bat gehitzen duzunean, horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
@@ -544,7 +547,7 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Erakundeak ziurtagiri-emaile bat instalatu dizu laneko profilean. Baliteke sareko trafiko segurua gainbegiratzea edo aldatzea."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Ziurtagiri-emaile bat dago instalatuta gailuan. Baliteke sareko trafiko segurua gainbegiratzea edo aldatzea."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake."</string>
- <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure laneko profileko trafikoa gainbegira dezake, baina ez zure profil pertsonalekoa."</string>
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratzaileak sarearen erregistroak aktibatu ditu; horrela, zure laneko profileko trafikoa gainbegira dezake, baina ez zure profil pertsonalekoa."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta zaude eta hark sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> eta <xliff:g id="VPN_APP_1">%2$s</xliff:g> aplikazioetara konektatuta zaude, eta haiek sareko jarduerak gainbegira ditzakete, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora dago konektatuta laneko profila, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Sakatu hau dardara ezartzeko."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sakatu hau audioa desaktibatzeko."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desaktibatu audioa"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktibatu audioa"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dardara"</string>
@@ -954,7 +959,7 @@
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Sakatu bateria eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Datu-konexioa desaktibatu nahi duzu?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> erabilita ezingo dituzu erabili datuak edo Internet. Wifi-sare baten bidez soilik konektatu ahal izango zara Internetera."</string>
- <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Uneko operadorea"</string>
+ <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Zure operadorea"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Aplikazio bat baimen-eskaera oztopatzen ari denez, ezarpenek ezin dute egiaztatu erantzuna."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakusteko baimena eman nahi diozu <xliff:g id="APP_0">%1$s</xliff:g> aplikazioari?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioaren informazioa irakur dezake."</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Gehitu"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> aplikazioak iradoki du"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Eguneratu dira kontrolatzeko aukerak"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Gailua blokeatuta"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodeak hizkiak edo ikurrak ditu"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Egiaztatu <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN okerra"</string>
@@ -1049,8 +1055,8 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string>
<string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string>
- <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu uneko saioa."</string>
- <string name="controls_media_active_session" msgid="1984383994625845642">"Ezin da ezkutatu uneko saioa."</string>
+ <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu saioa."</string>
+ <string name="controls_media_active_session" msgid="1984383994625845642">"Ezin da ezkutatu saioa."</string>
<string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>
<string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 72d7b50..04b14f1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"تا طلوع آفتاب"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ساعت <xliff:g id="TIME">%s</xliff:g> روشن میشود"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"تا<xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"کاهش روشنایی"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ارتباط میدان نزدیک (NFC)"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"«ارتباط میدان نزدیک» (NFC) غیرفعال است"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"«ارتباط میدان نزدیک» (NFC) فعال است"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"برای استفاده از NFC، قفل را باز کنید"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"این دستگاه به سازمان شما تعلق دارد"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"این دستگاه به <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> تعلق دارد"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"انگشتتان را از نماد تلفن تند بکشید"</string>
<string name="voice_hint" msgid="7476017460191291417">"برای «دستیار صوتی»، تند بکشید"</string>
<string name="camera_hint" msgid="4519495795000658637">"انگشتتان را از نماد دوربین تند بکشید"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. برای صامت کردن ضربه بزنید. ممکن است سرویسهای دسترسپذیری صامت شود."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. برای تنظیم روی لرزش، ضربه بزنید."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. برای صامت کردن ضربه بزنید."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"صامت کردن"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"باصدا کردن"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"لرزش"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"دستگاه قفل است"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"پین شامل حروف یا نماد است"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"تأیید <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"پین اشتباه است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 457d765..d08bfb5 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -125,7 +125,7 @@
<string name="use_ptp_button_title" msgid="7676427598943446826">"Käytä kamerana (PTP)"</string>
<string name="installer_cd_button_title" msgid="5499998592841984743">"Asenna Android File Transfer -sovellus Macille"</string>
<string name="accessibility_back" msgid="6530104400086152611">"Takaisin"</string>
- <string name="accessibility_home" msgid="5430449841237966217">"Aloituspainike"</string>
+ <string name="accessibility_home" msgid="5430449841237966217">"Aloitus"</string>
<string name="accessibility_menu" msgid="2701163794470513040">"Valikko"</string>
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"Esteettömyys"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"Näytön kääntäminen"</string>
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Auringonnousuun"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Päälle klo <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> asti"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Vähennä kirkkautta"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on poistettu käytöstä"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on käytössä"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> omistaa tämän laitteen"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Avaa puhelu pyyhkäisemällä."</string>
<string name="voice_hint" msgid="7476017460191291417">"Avaa ääniapuri pyyhkäisemällä kuvakkeesta."</string>
<string name="camera_hint" msgid="4519495795000658637">"Avaa kamera pyyhkäisemällä."</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Siirry värinätilaan napauttamalla."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Mykistä napauttamalla."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mykistä"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"poista mykistys"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"värinä"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Lisää"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Ehdottaja: <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Säätimet päivitetty"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Laite lukittu"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koodi sisältää kirjaimia tai symboleja"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Vahvista <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Väärä PIN-koodi"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3c4a9108..3d1ab93 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Actif à <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Réduire la luminosité"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC activée"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Balayez à partir de l\'icône pour accéder au téléphone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Balayez à partir de l\'icône pour accéder à l\'assist. vocale"</string>
<string name="camera_hint" msgid="4519495795000658637">"Balayez à partir de l\'icône pour accéder à l\'appareil photo"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Touchez pour activer les vibrations."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Touchez pour couper le son."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"désactiver le son"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggestion de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le NIP contient des lettres ou des symboles"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Vérifier <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"NIP incorrect"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 629cbba..c6d0674 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -238,7 +238,7 @@
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification masquée"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
- <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
+ <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Réglages rapides"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
<string name="accessibility_desc_settings" msgid="6728577365389151969">"Paramètres"</string>
<string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"Aperçu"</string>
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"À partir de <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Réduire la luminosité"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"La technologie NFC est activée"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Balayer pour téléphoner"</string>
<string name="voice_hint" msgid="7476017460191291417">"Balayer l\'écran depuis l\'icône pour l\'assistance vocale"</string>
<string name="camera_hint" msgid="4519495795000658637">"Balayer pour prendre une photo"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Appuyez pour mettre en mode vibreur."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Appuyez pour ignorer."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"couper le son"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"activer le vibreur"</string>
@@ -640,7 +645,7 @@
<string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"Afficher le pourcentage intégré de la batterie"</string>
<string name="show_battery_percentage_summary" msgid="9053024758304102915">"Affichez le pourcentage correspondant au niveau de la batterie dans l\'icône de la barre d\'état lorsque l\'appareil n\'est pas en charge."</string>
- <string name="quick_settings" msgid="6211774484997470203">"Configuration rapide"</string>
+ <string name="quick_settings" msgid="6211774484997470203">"Réglages rapides"</string>
<string name="status_bar" msgid="4357390266055077437">"Barre d\'état"</string>
<string name="overview" msgid="3522318590458536816">"Aperçu"</string>
<string name="demo_mode" msgid="263484519766901593">"Mode de démonstration de l\'interface du système"</string>
@@ -650,13 +655,13 @@
<string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</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 une tuile"</string>
- <string name="broadcast_tile" msgid="5224010633596487481">"Tuile de diffusion"</string>
+ <string name="add_tile" msgid="6239678623873086686">"Ajouter un bloc"</string>
+ <string name="broadcast_tile" msgid="5224010633596487481">"Bloc de diffusion"</string>
<string name="zen_alarm_warning_indef" msgid="5252866591716504287">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>, sauf si vous désactivez cette option avant."</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string>
<string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configuration rapide – <xliff:g id="TITLE">%s</xliff:g>"</string>
+ <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Réglages rapides – <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Point d\'accès"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string>
@@ -669,8 +674,8 @@
<string name="activity_not_found" msgid="8711661533828200293">"L\'application n\'est pas installée sur votre appareil."</string>
<string name="clock_seconds" msgid="8709189470828542071">"Afficher les secondes sur l\'horloge"</string>
<string name="clock_seconds_desc" msgid="2415312788902144817">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
- <string name="qs_rearrange" msgid="484816665478662911">"Réorganiser la fenêtre de configuration rapide"</string>
- <string name="show_brightness" msgid="6700267491672470007">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
+ <string name="qs_rearrange" msgid="484816665478662911">"Réorganiser les Réglages rapides"</string>
+ <string name="show_brightness" msgid="6700267491672470007">"Afficher la luminosité dans les Réglages rapides"</string>
<string name="experimental" msgid="3549865454812314826">"Paramètres expérimentaux"</string>
<string name="enable_bluetooth_title" msgid="866883307336662596">"Activer le Bluetooth ?"</string>
<string name="enable_bluetooth_message" msgid="6740938333772779717">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
@@ -878,20 +883,20 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Afficher les icônes de notification à faible priorité"</string>
<string name="other" msgid="429768510980739978">"Autre"</string>
- <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"supprimer la carte"</string>
- <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ajouter la carte à la fin"</string>
- <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer la carte"</string>
- <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter une carte"</string>
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"supprimer le bloc"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ajouter le bloc à la fin"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer le bloc"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter un bloc"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Déplacer vers <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Carte ajoutée"</string>
- <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Carte supprimée"</string>
- <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur de configuration rapide."</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloc ajouté"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloc supprimé"</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur Réglages rapides"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notification <xliff:g id="ID_1">%1$s</xliff:g> : <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ouvrir les paramètres."</string>
- <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Ouvrir la fenêtre de configuration rapide."</string>
- <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Fermer la fenêtre de configuration rapide."</string>
+ <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Ouvrir les Réglages rapides."</string>
+ <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Fermer les Réglages rapides."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Alarme définie."</string>
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Connecté en tant que <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"Aucun accès à Internet"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggérée par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le code contient des lettres ou des symboles"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Valider <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Code incorrect"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9383fb6..08841a2 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Ata o amencer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activarase ás: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Utilizarase ata as: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir brillo"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A opción NFC está desactivada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A opción NFC está activada"</string>
@@ -446,6 +447,8 @@
<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>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<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>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para establecer a vibración."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activar o son"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Engadir"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Control suxerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Actualizáronse os controis"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Disposit. bloqueado"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contén letras ou símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"O PIN é incorrecto"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index be62a29..867bc2f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"સ્ક્રીનશૉટ પર સ્ક્રોલ કરો"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"સ્ક્રીનશૉટ છોડી દો"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"સ્ક્રીનશૉટની સૌથી ઉપરની બાજુની સીમા"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"સ્ક્રીનશૉટની સૌથી નીચેની બાજુની સીમા"</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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"સૂર્યોદય સુધી"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> વાગ્યે ચાલુ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> વાગ્યા સુધી"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"બ્રાઇટનેસ ઘટાડો"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC અક્ષમ કરેલ છે"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC સક્ષમ કરેલ છે"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCનો ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ની માલિકીનું છે"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ફોન માટે આયકનમાંથી સ્વાઇપ કરો"</string>
<string name="voice_hint" msgid="7476017460191291417">"વૉઇસ સહાય માટે આયકનમાંથી સ્વાઇપ કરો"</string>
<string name="camera_hint" msgid="4519495795000658637">"કૅમેરા માટે આયકનમાંથી સ્વાઇપ કરો"</string>
@@ -546,8 +547,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. કંપન પર સેટ કરવા માટે ટૅપ કરો."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"મ્યૂટ કરો"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"અનમ્યૂટ કરો"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"વાઇબ્રેટ"</string>
@@ -1041,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"ડિવાઇસ લૉક કરેલું છે"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"પિનમાં અક્ષરો અથવા પ્રતીકોનો સમાવેશ થાય છે"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ને ચકાસો"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ખોટો પિન"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b487689..a357ad2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -93,8 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉट को स्क्रोल करें"</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" msgid="1500569103321300856">"स्क्रीनशॉट को ऊपर से काटने की सीमा"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"स्क्रीनशॉट को नीचे से काटने की सीमा"</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>
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सुबह तक चालू रहेगी"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> पर चालू हाेगी"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> तक चालू रहेगी"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"स्क्रीन की चमक कम करें"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"एनएफ़सी"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC बंद है"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC चालू है"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"इस डिवाइस का मालिकाना हक <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> के पास है"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"फ़ोन के लिए आइकॉन से स्वाइप करें"</string>
<string name="voice_hint" msgid="7476017460191291417">"\'आवाज़ से डिवाइस का इस्तेमाल\' आइकॉन से स्वाइप करें"</string>
<string name="camera_hint" msgid="4519495795000658637">"कैमरे के लिए आइकॉन से स्वाइप करें"</string>
@@ -546,7 +549,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>
@@ -627,6 +630,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. कंपन (वाइब्रेशन) पर सेट करने के लिए छूएं."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करने के लिए टैप करें."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करें"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्यूट करें"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"वाइब्रेशन की सुविधा चालू करें"</string>
@@ -1040,6 +1045,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"डिवाइस लॉक है"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिन में अक्षर या चिह्न शामिल होते हैं"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> की पुष्टि करें"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"गलत पिन"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 8f3d7c0..d8064ab 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanjenje svjetline"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Prijeđite prstom od ikone za telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Prijeđite prstom od ikone za glasovnu pomoć"</string>
<string name="camera_hint" msgid="4519495795000658637">"Prijeđite prstom od ikone za fotoaparat"</string>
@@ -628,6 +631,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Usluge pristupačnosti možda neće imati zvuk."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste postavili na vibraciju."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključivanje zvuka"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključivanje zvuka"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1044,6 +1049,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Preporuka s kanala <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4fda667..a736f88 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Napfelkeltéig"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Be: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Eddig: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Fényerő csökkentése"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Az NFC ki van kapcsolva"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Az NFC be van kapcsolva"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ez az eszköz a(z) <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tulajdonában van"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"A telefonhoz csúsztasson az ikonról"</string>
<string name="voice_hint" msgid="7476017460191291417">"A hangsegéd eléréséhez csúsztassa ujját az ikonról"</string>
<string name="camera_hint" msgid="4519495795000658637">"A fényképezőhöz csúsztasson az ikonról"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Koppintson a némításhoz. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Koppintson a rezgés beállításához."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Koppintson a némításhoz."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"némítás"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"némítás feloldása"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rezgés"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Hozzáadás"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> javasolta"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Vezérlők frissítve"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Az eszköz zárolva van"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"A PIN-kód betűket vagy szimbólumokat tartalmaz"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ellenőrzése"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Helytelen PIN-kód"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index f0c1f21..40ddf54 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Մինչև լուսաբաց"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Կմիանա՝ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Մինչև <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Նվազեցնել պայծառությունը"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Պայծառության նվազեցում"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-ն անջատված է"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-ն միացված է"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Այս սարքը պատկանում է «<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>» կազմակերպությանը"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Սահահարվածեք հեռախոսի պատկերակից"</string>
<string name="voice_hint" msgid="7476017460191291417">"Սահահարվածեք ձայնային հուշման պատկերակից"</string>
<string name="camera_hint" msgid="4519495795000658637">"Սահահարվածեք խցիկի պատկերակից"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s։ Հպեք՝ թրթռոցը միացնելու համար։"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s։ Հպեք՝ ձայնը անջատելու համար։"</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Հպեք՝ զանգակի ռեժիմը փոխելու համար"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"անջատել ձայնը"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"միացնել ձայնը"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"միացնել թրթռոցը"</string>
@@ -1038,6 +1041,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Սարքը կողպված է"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN կոդը տառեր և նշաններ է պարունակում"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Ստուգել <xliff:g id="DEVICE">%s</xliff:g> սարքը"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN կոդը սխալ է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 71ff39c..e20dd51 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sampai pagi"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktif pada <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Sampai <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Kurangi Kecerahan"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dinonaktifkan"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC diaktifkan"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Perangkat ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Geser dari ikon untuk telepon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Geser dari ikon untuk bantuan suara"</string>
<string name="camera_hint" msgid="4519495795000658637">"Geser dari ikon untuk kamera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketuk untuk menyetel agar bergetar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketuk untuk menonaktifkan."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Tanpa suara"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktifkan"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Tambahkan"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Disarankan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrol diperbarui"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Perangkat terkunci"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN berisi huruf atau simbol"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifikasi <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN salah"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 482338a..0c99420 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til sólarupprásar"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Virkt kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Draga úr birtu"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Slökkt á NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Kveikt á NFC"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Þetta tæki tilheyrir <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Strjúktu frá tákninu fyrir síma"</string>
<string name="voice_hint" msgid="7476017460191291417">"Strjúktu frá tákninu fyrir raddaðstoð"</string>
<string name="camera_hint" msgid="4519495795000658637">"Strjúktu frá tákninu fyrir myndavél"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ýttu til að stilla á titring."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ýttu til að þagga."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"þagga"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"hætta að þagga"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titringur"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Bæta við"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Tillaga frá <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Stýringar uppfærðar"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Tækið er læst"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN inniheldur bókstafi eða tákn"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Staðfesta <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Rangt PIN-númer"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0896d0c..527a695 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fino all\'alba"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Attivazione alle <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fino alle <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Riduci la luminosità"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC non attiva"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC attiva"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Questo dispositivo appartiene a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Scorri per accedere al telefono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Scorri dall\'icona per accedere a Voice Assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Scorri dall\'icona per accedere alla fotocamera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tocca per attivare la vibrazione."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tocca per disattivare l\'audio."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"disattiva l\'audio"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"riattiva l\'audio"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrazione"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Aggiungi"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggerito da <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlli aggiornati"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloccato"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Il PIN contiene lettere o simboli"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN errato"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e304dbe..9fc8b23 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"צילום מסך נגלל"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"סגירת צילום מסך"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"הקצה העליון"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"הקצה התחתון"</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>
@@ -418,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"עד הזריחה"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"יתחיל בשעה <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"עד <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"הפחתה של עוצמת הבהירות"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC מושבת"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC מופעל"</string>
@@ -452,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"יש לבטל את הנעילה כדי להשתמש ב-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"המכשיר הזה שייך לארגון שלך"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"המכשיר הזה שייך לארגון <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"החלק מהסמל כדי להפעיל את הטלפון"</string>
<string name="voice_hint" msgid="7476017460191291417">"החלק מהסמל כדי להפעיל את המסייע הקולי"</string>
<string name="camera_hint" msgid="4519495795000658637">"החלק מהסמל כדי להפעיל את המצלמה"</string>
@@ -552,8 +553,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -634,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. הקש כדי להשתיק. ייתכן ששירותי הנגישות מושתקים."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. הקש כדי להעביר למצב רטט."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. הקש כדי להשתיק."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ביטול ההשתקה"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"רטט"</string>
@@ -1053,6 +1055,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"המכשיר נעול"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"קוד האימות מכיל אותיות או סמלים"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"אימות <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"קוד גישה שגוי"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 05b1f76..1b18b5c 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"日の出まで"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>にオン"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>まで"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"明るさを下げる"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC は無効です"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC は有効です"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC を使用するには、ロックを解除してください"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"これは組織が所有するデバイスです"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"これは <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> が所有するデバイスです"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"右にスワイプして通話"</string>
<string name="voice_hint" msgid="7476017460191291417">"アイコンからスワイプして音声アシストを起動"</string>
<string name="camera_hint" msgid="4519495795000658637">"左にスワイプしてカメラを起動"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。タップしてバイブレーションに設定します。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。タップしてミュートします。"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ミュート"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ミュートを解除"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"バイブレーション"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"デバイス: ロック状態"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN に英字や記号を含める"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>の確認"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN が間違っています"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 5404e67..e2b9fac 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"მზის ამოსვლამდე"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ჩაირთოს <xliff:g id="TIME">%s</xliff:g>-ზე"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>-მდე"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"სიკაშკაშის შემცირება"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC გათიშულია"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ჩართულია"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"განბლოკეთ NFC-ის გამოსაყენებლად"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ამ მოწყობილობას ფლობს <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ტელეფონისთვის გადაფურცლეთ ხატულადან"</string>
<string name="voice_hint" msgid="7476017460191291417">"ხმოვანი დახმარებისთვის გადაფურცლეთ ხატულადან"</string>
<string name="camera_hint" msgid="4519495795000658637">"კამერისთვის გადაფურცლეთ ხატულადან"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. შეეხეთ დასადუმებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. შეეხეთ დასადუმებლად."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"დადუმება"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"დადუმების მოხსნა"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ვიბრაცია"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"მოწყობილ. ჩაკეტილია"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-კოდი შეიცავს ასოებს ან სიმბოლოებს"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"დაადასტურეთ <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN-კოდი არასწორია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 21c6201..1fbb8a5 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн шыққанға дейін"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Қосылу уақыты: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> дейін"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Жарықтығын азайту"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өшірулі"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC қосулы"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC пайдалану үшін құлыпты ашыңыз."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бұл құрылғы ұйымыңызға тиесілі."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Бұл құрылғы <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ұйымына тиесілі."</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Телефонды ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
<string name="voice_hint" msgid="7476017460191291417">"Дауыс көмекшісін ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камераны ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Діріл режимін орнату үшін түртіңіз."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дыбысын өшіру үшін түртіңіз."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дыбысын өшіру"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дыбысын қосу"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дірілдету"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Құрылғы құлыпталды."</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN коды әріптерден не таңбалардан құралады."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> растау"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN коды қате"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 567bfa8..e6f9668 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"រហូតដល់ពេលថ្ងៃរះ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"បើកនៅម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"រហូតដល់ម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"បន្ថយពន្លឺ"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"បានបិទ NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"បានបើក NFC"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ដោះសោ ដើម្បីប្រើ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ស្ថាប័នអ្នក"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"អូសចេញពីរូបតំណាងដើម្បីប្រើទូរស័ព្ទ"</string>
<string name="voice_hint" msgid="7476017460191291417">"អូសចេញពីរូបតំណាងដើម្បីប្រើជំនួយសំឡេង"</string>
<string name="camera_hint" msgid="4519495795000658637">"អូសចេញពីរូបតំណាងដើម្បីប្រើកាមេរ៉ា"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s ។ ចុចដើម្បីកំណត់ឲ្យញ័រ។"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s ។ ចុចដើម្បីបិទសំឡេង។"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"បិទសំឡេង"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"បើកសំឡេង"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ញ័រ"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"បានចាក់សោឧបករណ៍"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"កូដ PIN មានអក្សរ ឬនិមិត្តសញ្ញា"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"ផ្ទៀងផ្ទាត់ <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"កូដ PIN មិនត្រឹមត្រូវ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e0ea3c2..15abcaa 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ಸಮಯದಲ್ಲಿ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ವರೆಗೂ"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ಬಳಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ಈ ಸಾಧನವು <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ಗೆ ಸೇರಿದೆ"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ಫೋನ್ಗಾಗಿ ಐಕಾನ್ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ಧ್ವನಿ ಸಹಾಯಕ್ಕಾಗಿ ಐಕಾನ್ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ಕ್ಯಾಮರಾಗಾಗಿ ಐಕಾನ್ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್ ಮಾಡಬಹುದು."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ವೈಬ್ರೇಟ್ ಮಾಡಲು ಹೊಂದಿಸುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ಅನ್ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ವೈಬ್ರೇಟ್"</string>
@@ -1038,6 +1043,8 @@
<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>
+ <!-- no translation found for controls_tile_locked (731547768182831938) -->
+ <skip />
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ಪಿನ್ ಅಕ್ಷರಗಳು ಅಥವಾ ಸಂಕೇತಗಳನ್ನು ಒಳಗೊಂಡಿದೆ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ತಪ್ಪಾದ ಪಿನ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 64e4a69..78c2958 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"일출까지"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>에 켜짐"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>까지"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"밝기 낮추기"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 사용 중지됨"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 사용 설정됨"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"잠금 해제하여 NFC 사용"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"내 조직에 속한 기기입니다."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>에 속한 기기입니다."</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"전화 기능을 사용하려면 아이콘에서 스와이프하세요."</string>
<string name="voice_hint" msgid="7476017460191291417">"음성 지원을 사용하려면 아이콘에서 스와이프하세요."</string>
<string name="camera_hint" msgid="4519495795000658637">"카메라를 사용하려면 아이콘에서 스와이프하세요."</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. 탭하여 진동으로 설정하세요."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. 탭하여 음소거로 설정하세요."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"음소거"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"음소거 해제"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"진동"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"기기 잠김"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN에 문자나 기호가 포함됨"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> 확인"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"잘못된 PIN"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ecbcd55..7a4d7d2 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -94,7 +94,7 @@
<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_bottom_boundary" msgid="5657242629526407311">"Төмөнкү чеги"</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>
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн чыкканга чейин"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Саат <xliff:g id="TIME">%s</xliff:g> күйөт"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> чейин"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Экрандын жарыктыгын төмөндөтүү"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өчүрүлгөн"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC иштетилген"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC колдонуу үчүн түзмөктүн кулпусун ачыңыз"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бул түзмөк уюмуңузга таандык"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Бул түзмөк төмөнкүгө таандык: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Сүрөтчөнү сүрүп телефонго өтүңүз"</string>
<string name="voice_hint" msgid="7476017460191291417">"Сүрөтчөнү сүрүп үн жардамчысына өтүңүз"</string>
<string name="camera_hint" msgid="4519495795000658637">"Сүрөтчөнү сүрүп камерага өтүңүз"</string>
@@ -627,6 +630,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Үнүн өчүрүү үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дирилдөөгө коюу үчүн басыңыз."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Үнүн өчүрүү үчүн басыңыз."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"үнсүз"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"үнүн чыгаруу"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дирилдөө"</string>
@@ -1040,6 +1045,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Түзмөк кулпуланды"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN код тамгалардан же символдордон турат"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> түзмөгүн ырастаңыз"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN код туура эмес"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 98a75c2..7070fa1 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ຈົນກວ່າຕາເວັນຂຶ້ນ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ເປີດເວລາ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"ຈົນຮອດ <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ຫຼຸດຄວາມສະຫວ່າງ"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ປົດລັອກເພື່ອໃຊ້ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ອຸປະກອນນີ້ເປັນຂອງ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ປັດຈາກໄອຄອນສຳລັບໂທລະສັບ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ປັດຈາກໄອຄອນສຳລັບການຊ່ວຍທາງສຽງ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ປັດຈາກໄອຄອນສຳລັບກ້ອງຖ່າຍຮູບ"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນເຕືອນ."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ແຕະເພື່ອປິດສຽງ."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ປິດສຽງ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ເຊົາປິດສຽງ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ສັ່ນເຕືອນ"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"ອຸປະກອນຖືກລັອກໄວ້"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ປະກອບມີຕົວອັກສອນ ຫຼື ສັນຍາລັກ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"ຢັ້ງຢືນ <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ບໍ່ຖືກຕ້ອງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f4a2a0d..ff69e05 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -416,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Iki saulėtekio"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Iki <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Šviesumo mažinimas"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ALR"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"ALR išjungtas"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"ALR įjungtas"</string>
@@ -450,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Šis įrenginys priklauso „<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>“"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Perbraukite iš telefono piktogramos"</string>
<string name="voice_hint" msgid="7476017460191291417">"Perbraukite iš „Voice Assist“ piktogramos"</string>
<string name="camera_hint" msgid="4519495795000658637">"Perbraukite iš fotoaparato piktogramos"</string>
@@ -631,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Palieskite, kad nustatytumėte vibravimą."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Palieskite, kad nutildytumėte."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"nutildyti"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"įjungti garsą"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibruoti"</string>
@@ -1050,6 +1055,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Pridėti"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Siūlo „<xliff:g id="APP">%s</xliff:g>“"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Valdikliai atnaujinti"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Įrenginys užrakintas"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodą sudaro raidės arba simboliai"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> patvirtinimas"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Netinkamas PIN kodas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index caca22c..18816ad 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Līdz saullēktam"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Līdz plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Spilgtuma samazināšana"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ir atspējoti"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ir iespējoti"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Šī ierīce pieder organizācijai <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Lai lietotu tālruni, velciet no ikonas"</string>
<string name="voice_hint" msgid="7476017460191291417">"Lai lietotu balss palīgu, velciet no ikonas"</string>
<string name="camera_hint" msgid="4519495795000658637">"Lai lietotu kameru, velciet no ikonas"</string>
@@ -628,6 +631,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Pieskarieties, lai iestatītu vibrozvanu."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Pieskarieties, lai izslēgtu skaņu."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izslēgt skaņu"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ieslēgt skaņu"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrēt"</string>
@@ -1044,6 +1049,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Pievienot"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Ieteica: <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Vadīklas atjauninātas"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Ierīce ir bloķēta"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ietver burtus vai simbolus."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifikācija: <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Nepareizs PIN"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index b3b4a45..59fc2d4 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрејсонце"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Се вклучува во <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Намали ја осветленоста"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC е оневозможено"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC е овозможено"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отклучете за да користите NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Уредов е во сопственост на организацијата"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Уредов е во сопственост на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Повлечете од иконата за телефонот"</string>
<string name="voice_hint" msgid="7476017460191291417">"Повлечете од иконата за гласовна помош"</string>
<string name="camera_hint" msgid="4519495795000658637">"Повлечете од иконата за камерата"</string>
@@ -505,7 +508,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>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Допрете за да исклучите звук. Можеби ќе се исклучи звукот на услугите за достапност."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Допрете за да се постави на вибрации."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Допрете за да се исклучи звукот."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"исклучен звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"вклучен звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрации"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Уредот е заклучен"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-кодот содржи букви или симболи"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Потврдете го <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Погрешен PIN"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 420de5b..44883d6d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"സ്ക്രീൻഷോട്ട് സ്ക്രോൾ ചെയ്യുക"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"സ്ക്രീൻഷോട്ട് ഡിസ്മിസ് ചെയ്യുക"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"സ്ക്രീൻഷോട്ട് പ്രിവ്യു"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"മുകളിലുള്ള അതിർത്തി"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ചുവടെയുള്ള അതിർത്തി"</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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"സൂര്യോദയം വരെ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> വരെ"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"തെളിച്ചം കുറയ്ക്കുക"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC പ്രവർത്തനക്ഷമമാക്കി"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ഈ ഉപകരണം <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> എന്ന സ്ഥാപനത്തിന്റേതാണ്"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ഫോൺ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
<string name="voice_hint" msgid="7476017460191291417">"വോയ്സ് അസിസ്റ്റിനായുള്ള ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
<string name="camera_hint" msgid="4519495795000658637">"ക്യാമറ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
@@ -546,8 +547,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"മ്യൂട്ട് ചെയ്യുക"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"അൺമ്യൂട്ട് ചെയ്യുക"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"വൈബ്രേറ്റ് ചെയ്യുക"</string>
@@ -1041,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"ഉപകരണം ലോക്ക് ചെയ്തു"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"പിന്നിൽ അക്ഷരങ്ങളോ ചിഹ്നങ്ങളോ അടങ്ങിയിരിക്കുന്നു"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> പരിശോധിച്ചുറപ്പിക്കുക"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"പിൻ തെറ്റാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 63547d5..efb2711 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Нар мандах хүртэл"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-д"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> хүртэл"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Гэрэлтүүлгийг багасгах"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Гэрэлтүүлгийг багасгах"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-г цуцалсан"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-г идэвхжүүлсэн"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC-г ашиглахын тулд түгжээг тайлна уу"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Энэ төхөөрөмж <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-д харьяалагддаг"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Утсыг гаргахын тулд дүрс тэмдгээс шудрах"</string>
<string name="voice_hint" msgid="7476017460191291417">"Дуут туслахыг нээхийн тулд дүрс тэмдгээс шудрах"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камер нээхийн тулд дүрс тэмдгийг шудрах"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Чичиргээнд тохируулахын тулд товшино уу."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дууг хаахын тулд товшино уу."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Хонхны горимыг өөрчлөхийн тулд товшино уу"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дууг хаах"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дууг нээх"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"чичрэх"</string>
@@ -1038,6 +1041,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Төхөөрөмжийг түгжсэн"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН нь үсэг эсвэл дүрс тэмдэгт агуулдаг"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>-г бататгах"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ПИН код буруу байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index de0e7be..fcff3df 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉटवर स्क्रोल करा"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट डिसमिस करा"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉटचे पूर्वावलोकन"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"सर्वात वरची सीमा"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"तळाची सीमा"</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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयापर्यंत"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> वाजता सुरू होते"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> पर्यंत"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ब्राइटनेस कमी करा"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC अक्षम केले आहे"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC सक्षम केले आहे"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC वापरण्यासाठी स्क्रीन अनलॉक करा"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"हे डिव्हाइस तुमच्या संस्थेचे आहे"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> चे आहे"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"फोनसाठी चिन्हावरून स्वाइप करा"</string>
<string name="voice_hint" msgid="7476017460191291417">"व्हॉइस सहाय्यासाठी चिन्हावरून स्वाइप करा"</string>
<string name="camera_hint" msgid="4519495795000658637">"कॅमेर्यासाठी चिन्हावरून स्वाइप करा"</string>
@@ -546,8 +547,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा म्यूट केल्या जाऊ शकतात."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करण्यासाठी टॅप करा."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करा"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"म्यूट काढून टाका"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"व्हायब्रेट करा"</string>
@@ -1041,6 +1043,8 @@
<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>
+ <!-- no translation found for controls_tile_locked (731547768182831938) -->
+ <skip />
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरे किंवा चिन्हे आहेत"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ची पडताळणी करा"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"चुकीचा पिन"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 319dbde..e723ec6 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hingga matahari trbt"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Dihidupkan pada <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hingga <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Kurangkan Kecerahan"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dilumpuhkan"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC didayakan"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Peranti ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Leret dari ikon untuk telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Leret dari ikon untuk bantuan suara"</string>
<string name="camera_hint" msgid="4519495795000658637">"Leret dari ikon untuk kamera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketik untuk menetapkan pada getar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketik untuk meredam."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"redam"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"nyahredam"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Tambah"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Dicadangkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kawalan dikemas kini"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Peranti dikunci"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN mengandungi huruf atau simbol"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Sahkan <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN salah"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 15ddf59..c57a94c 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"နေထွက်ချိန် အထိ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> တွင် ဖွင့်မည်"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> အထိ"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"တောက်ပမှုကို လျှော့ရန်"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ကို ပိတ်ထားသည်"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ကို ဖွင့်ထားသည်"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ကို အသုံးပြုရန် လော့ခ်ဖွင့်ပါ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ဤစက်ကို <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> က ပိုင်ဆိုင်သည်"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ဖုန်းအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
<string name="voice_hint" msgid="7476017460191291417">"အသံအကူအညီအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ကင်မရာအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s။ တုန်ခါခြင်းသို့ သတ်မှတ်ရန်တို့ပါ။"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s။ အသံတိတ်ရန် တို့ပါ။"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"အသံတိတ်ရန်"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"အသံဖွင့်ရန်"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"တုန်ခါမှု"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"စက်ကိုလော့ခ်ချထားသည်"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ပင်နံပါတ်တွင် စာလုံး သို့မဟုတ် သင်္ကေတများပါဝင်သည်"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ကို အတည်ပြုခြင်း"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ပင်နံပါတ် မှားနေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1c2fa8a..997147d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til soloppgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Slås på klokken <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduser lysstyrken"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er slått av"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er slått på"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enheten tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Sveip ikonet for å åpne telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Sveip fra ikonet for å åpne talehjelp"</string>
<string name="camera_hint" msgid="4519495795000658637">"Sveip ikonet for å åpne kamera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trykk for å angi vibrasjon."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trykk for å slå av lyden."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"kutt lyden"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på lyden"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Legg til"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Foreslått av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollene er oppdatert"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Enheten er låst"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koden inneholder bokstaver eller symboler"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Bekreft <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Feil PIN-kode"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 3ab0136f..e03ee5b 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रिनसट स्क्रोल गर्नुहोस्"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रिनसट हटाउनुहोस्"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रिनसटको पूर्वावलोकन"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"सिरानको सीमा"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"फेदको सीमा"</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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयसम्म"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> मा सक्रिय"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> सम्म"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"स्क्रिनको चमक घटाउनुहोस्"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC लाई असक्षम पारिएको छ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC लाई सक्षम पारिएको छ"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> को स्वामित्वमा छ"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"फोनको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
<string name="voice_hint" msgid="7476017460191291417">"आवाज सहायताका लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
<string name="camera_hint" msgid="4519495795000658637">"क्यामेराको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
@@ -546,8 +547,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। म्यूट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। कम्पन मोडमा सेट गर्न ट्याप गर्नुहोस्।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। म्यूट गर्न ट्याप गर्नुहोस्।"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्युट गर्नुहोस्"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्युट गर्नुहोस्"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"कम्पन गर्नुहोस्"</string>
@@ -1041,6 +1043,8 @@
<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>
+ <!-- no translation found for controls_tile_locked (731547768182831938) -->
+ <skip />
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN मा अक्षर वा चिन्हहरू समाविष्ट हुन्छन्"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> पुष्टि गर्नुहोस्"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN मिलेन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index dcadbf5..8ffc3f4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Helderheid verlagen"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is uitgeschakeld"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is ingeschakeld"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Dit apparaat is eigendom van <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swipen voor telefoon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipen vanaf icoon voor spraakassistent"</string>
<string name="camera_hint" msgid="4519495795000658637">"Vegen voor camera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te dempen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om in te stellen op trillen."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om geluid uit te zetten."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"geluid uit"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"geluid aanzetten"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"trillen"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Toevoegen"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Voorgesteld door <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Bedieningselementen geüpdated"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Apparaat vergrendeld"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pincode bevat letters of symbolen"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> verifiëren"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Onjuiste pincode"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 955c08a..f03c31d 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ସକାଳ ପର୍ଯ୍ୟନ୍ତ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ରେ ଚାଲୁ ହେବ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ଉଜ୍ଜ୍ୱଳତା କମାନ୍ତୁ"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ସକ୍ଷମ କରାଯାଇଛି"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ର ଅଟେ"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ଫୋନ୍ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ଭଏସ୍ ସହାୟକ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="camera_hint" msgid="4519495795000658637">"କ୍ୟାମେରା ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ମ୍ୟୁଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍ ମ୍ୟୁଟ୍ କରାଯାଇପାରେ।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ଭାଇବ୍ରେଟରେ ସେଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ମ୍ୟୁଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ମ୍ୟୁଟ୍"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ଅନ୍-ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ଭାଇବ୍ରେଟ୍"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"ଡିଭାଇସ୍ ଲକ୍ ହୋଇଯାଇଛି"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PINରେ ଅକ୍ଷର କିମ୍ୱା ପ୍ରତୀକଗୁଡ଼ିକ ଥାଏ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ଭୁଲ PIN"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 47f56bd..459b163 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਪੂਰਵ-ਝਲਕ"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"ਉੱਪਰ ਦੀ ਸੀਮਾ"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ਹੇਠਾਂ ਦੀ ਸੀਮਾ"</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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਚਾਲੂ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਤੱਕ"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ਚਮਕ ਘਟਾਓ"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ਫ਼ੋਨ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ਕੈਮਰੇ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
@@ -546,8 +547,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ਥਰਥਰਾਹਟ \'ਤੇ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ਮਿਊਟ ਕਰੋ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ਅਣਮਿਊਟ ਕਰੋ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ਥਰਥਰਾਹਟ"</string>
@@ -1041,6 +1043,8 @@
<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>
+ <!-- no translation found for controls_tile_locked (731547768182831938) -->
+ <skip />
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ਪਿੰਨ ਵਿੱਚ ਅੱਖਰ ਜਾਂ ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਹਨ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ਗਲਤ ਪਿੰਨ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 59c9f52..e16b5ec 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"Przewiń zrzut ekranu"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zamknij zrzut ekranu"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Podgląd zrzutu ekranu"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"Górna granica"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Dolna granica"</string>
<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>
@@ -418,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do wschodu słońca"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Włącz o <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Zmniejsz jasność"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"Komunikacja NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Komunikacja NFC jest wyłączona"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Komunikacja NFC jest włączona"</string>
@@ -452,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Właściciel tego urządzenia: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Aby włączyć telefon, przesuń palcem od ikony"</string>
<string name="voice_hint" msgid="7476017460191291417">"Aby uzyskać pomoc głosową, przesuń palcem od ikony"</string>
<string name="camera_hint" msgid="4519495795000658637">"Przesuń palcem od ikony, by włączyć aparat"</string>
@@ -552,8 +553,7 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Twoja organizacja zainstalowała urząd certyfikacji w Twoim profilu służbowym. Zabezpieczony ruch w sieci może być monitorowany i zmieniany."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Urząd certyfikacji zainstalowany na tym urządzeniu. Twój zabezpieczony ruch w sieci może być monitorowany i zmieniany."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim urządzeniu."</string>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim profilu służbowym, ale nie na profilu osobistym."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Łączysz się z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Łączysz się z aplikacjami <xliff:g id="VPN_APP_0">%1$s</xliff:g> i <xliff:g id="VPN_APP_1">%2$s</xliff:g>, które mogą monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Twój profil służbowy jest połączony z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
@@ -634,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Kliknij, by wyciszyć. Ułatwienia dostępu mogą być wyciszone."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Kliknij, by włączyć wibracje."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Kliknij, by wyciszyć."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"wycisz"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"wyłącz wyciszenie"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"włącz wibracje"</string>
@@ -1053,6 +1055,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugestia: <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Zaktualizowano elementy sterujące"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Urządzenie zablokowane"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kod PIN zawiera litery lub symbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Sprawdź urządzenie <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Nieprawidłowy kod PIN"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index fca802d..efe0f06 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir brilho"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -791,7 +796,7 @@
<string name="keyboard_key_media_stop" msgid="1509943745250377699">"Parar"</string>
<string name="keyboard_key_media_next" msgid="8502476691227914952">"Avançar"</string>
<string name="keyboard_key_media_previous" msgid="5637875709190955351">"Anterior"</string>
- <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Retroceder"</string>
+ <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Voltar"</string>
<string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"Avançar rapidamente"</string>
<string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
<string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9b4d45b..3a82feb 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até ao amanhecer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativado à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir o brilho"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"O NFC está desativado"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"O NFC está ativado"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à entidade <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Deslize rapid. a partir do ícone para aceder ao telemóvel"</string>
<string name="voice_hint" msgid="7476017460191291417">"Deslize rapid. a partir do ícone para aceder ao assist. voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Deslize rapidamente a partir do ícone para aceder à câmara"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para ativar a vibração."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para desativar o som."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar som"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"reativar som"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlos atualizados"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos."</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Validar <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index fca802d..efe0f06 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir brilho"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -791,7 +796,7 @@
<string name="keyboard_key_media_stop" msgid="1509943745250377699">"Parar"</string>
<string name="keyboard_key_media_next" msgid="8502476691227914952">"Avançar"</string>
<string name="keyboard_key_media_previous" msgid="5637875709190955351">"Anterior"</string>
- <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Retroceder"</string>
+ <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Voltar"</string>
<string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"Avançar rapidamente"</string>
<string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
<string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3a06921..18093b4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Până la răsărit"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activată la <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Până la <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduceți luminozitatea"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Serviciul NFC este dezactivat"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Serviciul NFC este activat"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Glisați dinspre telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Glisați dinspre pictogramă pentru asistentul vocal"</string>
<string name="camera_hint" msgid="4519495795000658637">"Glisați pentru a fotografia"</string>
@@ -628,6 +631,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Atingeți pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Atingeți pentru a seta pe vibrații."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Atingeți pentru a dezactiva sunetul."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"dezactivați sunetul"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activați sunetul"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrații"</string>
@@ -1044,6 +1049,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Adăugați"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugerat de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"S-au actualizat comenzile"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Dispozitiv blocat"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Codul PIN conține litere sau simboluri"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verificați <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Cod PIN greșit"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a81401a..a9f7c02 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -416,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До рассвета"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Включить в <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Уменьшение яркости"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"Модуль NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Модуль NFC отключен"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Модуль NFC включен"</string>
@@ -450,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Чтобы использовать NFC, разблокируйте устройство."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Это устройство принадлежит вашей организации"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Этим устройством владеет организация \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Телефон: проведите от значка"</string>
<string name="voice_hint" msgid="7476017460191291417">"Аудиоподсказки: проведите от значка"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камера: проведите от значка"</string>
@@ -631,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Нажмите, чтобы выключить звук. Специальные возможности могут прекратить работу."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Нажмите, чтобы включить вибрацию."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Нажмите, чтобы выключить звук."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"отключить звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"включить звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"включить вибрацию"</string>
@@ -1050,6 +1055,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Устройство заблокировано"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код содержит буквы или символы"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Подтвердите устройство \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Неверный PIN-код"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index f62eae0..5134e04 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"හිරු නගින තෙක්"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ට ක්රියාත්මකයි"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> තෙක්"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"දීප්තිය අඩු කරන්න"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"දීප්තිය අඩු කරන්න"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC අබලයි"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC සබලයි"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC භාවිත කිරීමට අගුලු හරින්න"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"මෙම උපාංගය <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> සංවිධානයට අයිතිය"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"දුරකථනය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
<string name="voice_hint" msgid="7476017460191291417">"හඬ සහාය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
<string name="camera_hint" msgid="4519495795000658637">"කැමරාව සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්රවේශ්යතා සේවා නිහඬ කළ හැකිය."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. කම්පනය කිරීමට සකස් කිරීමට තට්ටු කරන්න."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"නාදකය වෙනස් කිරීමට තට්ටු කරන්න"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"නිහඬ කරන්න"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"නිශ්ශබ්දතාවය ඉවත් කරන්න"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"කම්පනය"</string>
@@ -1038,6 +1041,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"උපාංගය අගුලු දමා ඇත"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN හි අකුරු හෝ සංකේත අඩංගු වේ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> සත්යාපනය කරන්න"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"වැරදි PIN එකකි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 927b2ac..d514b66 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -416,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do východu slnka"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapne sa o <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Znížiť jas"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je deaktivované"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je aktivované"</string>
@@ -450,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zariadení patrí organizácii <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Telefón otvoríte prejdením prstom od ikony"</string>
<string name="voice_hint" msgid="7476017460191291417">"Hlasového asistenta otvoríte prejdením prstom od ikony"</string>
<string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otvoríte prejdením prstom od ikony"</string>
@@ -631,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnite zvuk. Služby dostupnosti je možné stlmiť."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrovanie."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnite zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"zapnite vibrovanie"</string>
@@ -1050,6 +1055,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Pridať"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Navrhuje <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládanie bolo aktualizované"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Uzamknuté zariadenie"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN obsahuje písmená či symboly"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>, overenie"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Nesprávny PIN"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 881ba91..b7b2dd0 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -416,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do sončnega vzhoda"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Vklop ob <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Zmanjšanje svetlosti"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Tehnologija NFC je onemogočena"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Tehnologija NFC je omogočena"</string>
@@ -450,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ta naprava pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Povlecite z ikone za telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Povlecite z ikone za glasovnega pomočnika"</string>
<string name="camera_hint" msgid="4519495795000658637">"Povlecite z ikone za fotoaparat"</string>
@@ -631,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dotaknite se, če želite nastaviti vibriranje."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dotaknite se, če želite izklopiti zvok."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izklop zvoka"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vklop zvoka"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1050,6 +1055,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Predlagala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrolniki so posodobljeni"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Naprava je zaklenjena"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Koda PIN vsebuje črke ali simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Preverjanje naprave <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Napačna koda PIN"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 29d1661..9f4c1e1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Deri në lindje të diellit"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktiv në <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Deri në <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Redukto ndriçimin"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC është çaktivizuar"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC është aktivizuar"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Kjo pajisje i përket <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Rrëshqit për të hapur telefonin"</string>
<string name="voice_hint" msgid="7476017460191291417">"Rrëshqit për të hapur ndihmën zanore"</string>
<string name="camera_hint" msgid="4519495795000658637">"Rrëshqit për të hapur kamerën"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trokit për ta vendosur në dridhje."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trokit për ta çaktivizuar."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"çaktivizo audion"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktivizo audion"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"lësho dridhje"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Shto"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Sugjeruar nga <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollet u përditësuan"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Pajisja është e kyçur"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kodi PIN përmban shkronja ose simbole"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifiko <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Kod PIN i gabuar"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c021bfa..5c2fbac 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -414,7 +414,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изласка сунца"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Укључује се у <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Смањи осветљеност"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC је онемогућен"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC је омогућен"</string>
@@ -448,6 +449,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Откључајте да бисте користили NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Овај уређај припада организацији"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Овај уређај припада организацији <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Превуците од иконе за телефон"</string>
<string name="voice_hint" msgid="7476017460191291417">"Превуците од иконе за гласовну помоћ"</string>
<string name="camera_hint" msgid="4519495795000658637">"Превуците од иконе за камеру"</string>
@@ -628,6 +631,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Додирните да бисте искључили звук. Звук услуга приступачности ће можда бити искључен."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Додирните да бисте подесили на вибрацију."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Додирните да бисте искључили звук."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"искључите звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"укључите звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрација"</string>
@@ -1044,6 +1049,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Уређај је закључан"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN садржи слова или симболе"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Верификујте: <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Погрешан PIN"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e38d7cd..5ca41ed 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Till soluppgången"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktivera kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Till <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Minska ljusstyrkan"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC är inaktiverat"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC är aktiverat"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Den här enheten tillhör <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Svep från ikonen och öppna telefonen"</string>
<string name="voice_hint" msgid="7476017460191291417">"Svep från ikonen och öppna röstassistenten"</string>
<string name="camera_hint" msgid="4519495795000658637">"Svep från ikonen och öppna kameran"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryck här om du vill aktivera vibrationsläget."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryck här om du vill stänga av ljudet."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stänga av ljudet"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på ljudet"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Lägg till"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Förslag från <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Snabbkontroller uppdaterade"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Enheten är låst"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden innehåller bokstäver eller symboler"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Verifiera <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Fel pinkod"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a775d14..768e10c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hadi macheo"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Itawashwa saa <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hadi saa <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Punguza Ung\'aavu"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC imezimwa"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC imewashwa"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Kifaa hiki kinamilikiwa na <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Telezesha kidole kutoka kwa aikoni ili ufikie simu"</string>
<string name="voice_hint" msgid="7476017460191291417">"Telezesha kidole kutoka aikoni ili upate mapendekezo ya sauti"</string>
<string name="camera_hint" msgid="4519495795000658637">"Telezesha kidole kutoka aikoni ili ufikie kamera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Gusa ili uweke mtetemo."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Gusa ili usitishe."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"zima sauti"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"washa sauti"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tetema"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Weka"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Kimependekezwa na <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Umesasisha vidhibiti"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Kifaa kimefungwa"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ina herufi au alama"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Thibitisha <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Nambari ya PIN si sahihi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 335a529..2ea5a6a 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"காலை வரை"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>க்கு ஆன் செய்"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> வரை"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ஒளிர்வைக் குறை"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC முடக்கப்பட்டது"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC இயக்கப்பட்டது"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCயைப் பயன்படுத்த அன்லாக் செய்யவும்"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"இந்த சாதனம் <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> நிறுவனத்துக்கு சொந்தமானது"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ஃபோனிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
<string name="voice_hint" msgid="7476017460191291417">"குரல் உதவிக்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
<string name="camera_hint" msgid="4519495795000658637">"கேமராவிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும்."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ஒலியடக்க, தட்டவும்."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ஒலியடக்கும்"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ஒலி இயக்கும்"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"அதிர்வுறும்"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"சாதனம் பூட்டப்பட்டது"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"பின்னில் எழுத்துகள் அல்லது குறிகள் உள்ளன"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ஐச் சரிபார்த்தல்"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"தவறான பின்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 8013d6e..03af2a0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"స్క్రీన్షాట్కు స్క్రోల్ చేయండి"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"స్క్రీన్షాట్ను విస్మరించు"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"స్క్రీన్షాట్ ప్రివ్యూ"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"ఎగువ సరిహద్దు"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"దిగువ సరిహద్దు"</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>
@@ -414,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"సూర్యోదయం వరకు"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> కు ఆన్ అవుతుంది"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> వరకు"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ప్రకాశాన్ని తగ్గించండి"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC నిలిపివేయబడింది"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ప్రారంభించబడింది"</string>
@@ -448,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCని ఉపయోగించడానికి అన్లాక్ చేయండి"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ఈ పరికరం మీ సంస్థకు చెందినది"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>కు చెందినది"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"ఫోన్ కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
<string name="voice_hint" msgid="7476017460191291417">"వాయిస్ అసిస్టెంట్ చిహ్నం నుండి స్వైప్"</string>
<string name="camera_hint" msgid="4519495795000658637">"కెమెరా కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
@@ -546,8 +547,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>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <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>
@@ -628,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. వైబ్రేట్ అయ్యేలా సెట్ చేయడం కోసం నొక్కండి."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. మ్యూట్ చేయడానికి నొక్కండి."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"మ్యూట్ చేయి"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్మ్యూట్ చేయి"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"వైబ్రేట్"</string>
@@ -1041,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"పరికరంలాక్ చేయబడింది"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"పిన్ అక్షరాలను లేదా చిహ్నాలను కలిగి ఉంది"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ను వెరిఫై చేయండి"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"పిన్ తప్పు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c55b7f0..5e37ed8 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"จนพระอาทิตย์ขึ้น"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"เปิดเวลา <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"จนถึง <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ลดความสว่าง"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ถูกปิดใช้งาน"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"เปิดใช้งาน NFC แล้ว"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ปลดล็อกเพื่อใช้ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> เป็นเจ้าของอุปกรณ์นี้"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"เลื่อนไอคอนโทรศัพท์"</string>
<string name="voice_hint" msgid="7476017460191291417">"เลื่อนไอคอนตัวช่วยเสียง"</string>
<string name="camera_hint" msgid="4519495795000658637">"เลื่อนไอคอนกล้อง"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s แตะเพื่อตั้งค่าให้สั่น"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s แตะเพื่อปิดเสียง"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ปิดเสียง"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"เปิดเสียง"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"สั่น"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"อุปกรณ์ถูกล็อก"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ประกอบด้วยตัวอักษรหรือสัญลักษณ์"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"ยืนยัน <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ไม่ถูกต้อง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 33bd659..18313e4 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hanggang sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ma-o-on nang <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Bawasan ang Liwanag"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Naka-disable ang NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Naka-enable ang NFC"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Pagmamay-ari ng <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ang device na ito"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Mag-swipe mula sa icon para sa telepono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Mag-swipe mula sa icon para sa voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Mag-swipe mula sa icon para sa camera"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. I-tap upang itakda na mag-vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. I-tap upang i-mute."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"i-mute"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"i-unmute"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"i-vibrate"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Idagdag"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Iminungkahi ng <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Na-update na ang mga kontrol"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Naka-lock ang device"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"May mga titik o simbolo ang PIN"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"I-verify ang <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Maling PIN"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4bacfb9..6b3015c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sabaha kadar"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Açılacağı saat: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Şu saate kadar: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Parlaklığı Azalt"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC devre dışı"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC etkin"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> adlı kuruluşa ait"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Telefon için, simgeden hızlıca kaydırın"</string>
<string name="voice_hint" msgid="7476017460191291417">"Sesli yardım için, simgeden hızlıca kaydırın"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kamera için, simgeden hızlıca kaydırın"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sesi kapatmak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Titreşime ayarlamak için dokunun."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sesi kapatmak için dokunun."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"sesi kapat"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"sesi aç"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titreşim"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Ekle"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tarafından önerildi"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Denetimler güncellendi"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilitlendi"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN, harf veya simge içerir"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Yanlış PIN"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4a0746c..12b4830 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -416,7 +416,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До сходу сонця"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Вмикається о <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Зменшувати яскравість"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC вимкнено"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ввімкнено"</string>
@@ -450,6 +451,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Цей пристрій належить організації \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Телефон: проведіть пальцем від значка"</string>
<string name="voice_hint" msgid="7476017460191291417">"Голосові підказки: проведіть пальцем від значка"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камера: проведіть пальцем від значка"</string>
@@ -631,6 +634,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Торкніться, щоб вимкнути звук. Спеціальні можливості може бути вимкнено."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Торкніться, щоб налаштувати вібросигнал."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Торкніться, щоб вимкнути звук."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"вимкнути звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"увімкнути звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"увімкнути вібросигнал"</string>
@@ -1050,6 +1055,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Пристрій заблоковано"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код містить літери чи символи"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Неправильний PIN-код"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index f2e0273..3668f7e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"طلوع آفتاب تک"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"آن ہوگی بوقت <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> تک"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"چمک کم کریں"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC غیر فعال ہے"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC فعال ہے"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC استعمال کرنے کیلئے غیر مقفل کریں"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"یہ آلہ آپ کی تنظیم کا ہے"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"یہ آلہ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> کا ہے"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"فون کیلئے آئیکن سے سوائپ کریں"</string>
<string name="voice_hint" msgid="7476017460191291417">"صوتی معاون کیلئے آئیکن سے سوائپ کریں"</string>
<string name="camera_hint" msgid="4519495795000658637">"کیمرہ کیلئے آئیکن سے سوائپ کریں"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"خاموش کریں"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"غیر خاموش کریں"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"وائبریٹ"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"آلہ مقفل کر دیا گیا"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN میں حروف یا علامات شامل ہیں"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> کی تصدیق کریں"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"غلط PIN"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index fab65b1..0732c7f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -93,10 +93,8 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"Skrinshotni aylantirish"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"Skrinshotni yopish"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Skrinshotga razm solish"</string>
- <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
- <skip />
- <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
- <skip />
+ <string name="screenshot_top_boundary" msgid="1500569103321300856">"Yuqori chegara"</string>
+ <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Quyi chegara"</string>
<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>
@@ -414,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Quyosh chiqqunicha"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> da yoqiladi"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> gacha"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Yorqinlikni pasaytirish"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Yorqinlikni pasaytirish"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC o‘chiq"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC yoniq"</string>
@@ -448,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu qurilma <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tashkilotiga tegishli"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Telefonni ochish uchun suring"</string>
<string name="voice_hint" msgid="7476017460191291417">"Ovozli yordam: belgidan boshlab suring"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kamerani ochish uchun suring"</string>
@@ -546,8 +546,7 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Tashkilotingiz ishchi profilingizga CA sertifikatini o‘rnatdi. U himoyalangan tarmoq trafigini nazorat qilishi va o‘zgartirishi mumkin."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Qurilmada CA sertifikati o‘rnatilgan. U himoyalangan tarmoq trafigini nazorat qilishi va o‘zgartirishi mumkin."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administrator qurilmangizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi."</string>
- <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
- <skip />
+ <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administrator ish profilingizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi (shaxsiy profildan maʼlumotlar olinmaydi)."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> va <xliff:g id="VPN_APP_1">%2$s</xliff:g> ilovalari ishga tushirilgan. Ular tarmoqdagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Ishchi profilingizda tarmoqdagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin bo‘lgan <xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan."</string>
@@ -628,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ovozini o‘chirish uchun ustiga bosing. Maxsus imkoniyatlar ishlamasligi mumkin."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tebranishni yoqish uchun ustiga bosing."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ovozsiz qilish uchun ustiga bosing."</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Jiringlagich rejimini oʻzgartirish uchun bosing"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ovozsiz qilish"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ovozni yoqish"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tebranish"</string>
@@ -1041,6 +1041,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Kiritish"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> taklif etgan"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Boshqaruv elementlari yangilandi"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Qurilma qulflandi"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Harflar yoki maxsus belgilardan iborat PIN kod"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Tekshirish: <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN kod xato"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 366f755..cc89303 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Cho đến khi trời sáng"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bật vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Cho đến <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Giảm độ sáng"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC đã được tắt"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC đã được bật"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Thiết bị này thuộc về <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Vuốt từ biểu tượng để mở điện thoại"</string>
<string name="voice_hint" msgid="7476017460191291417">"Vuốt từ biểu tượng để mở trợ lý thoại"</string>
<string name="camera_hint" msgid="4519495795000658637">"Vuốt từ biểu tượng để mở máy ảnh"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Nhấn để đặt chế độ rung."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Nhấn để tắt tiếng."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"tắt tiếng"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"bật tiếng"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rung"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Thêm"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Do <xliff:g id="APP">%s</xliff:g> đề xuất"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Đã cập nhật các tùy chọn điều khiển"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Đã khóa thiết bị"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Mã PIN chứa các ký tự hoặc ký hiệu"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Xác minh <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Mã PIN sai"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c25ad27..92f9e67 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"在日出时关闭"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"在<xliff:g id="TIME">%s</xliff:g> 开启"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"直到<xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"调低亮度"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已启用"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"需要解锁才能使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此设备归贵单位所有"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"此设备归<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>所有"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"滑动图标即可拨打电话"</string>
<string name="voice_hint" msgid="7476017460191291417">"滑动图标即可打开语音助理"</string>
<string name="camera_hint" msgid="4519495795000658637">"滑动图标即可打开相机"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。点按即可设为振动。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。点按即可设为静音。"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"静音"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消静音"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"振动"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"设备已锁定"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 码由字母或符号组成"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"验证<xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 码错误"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index aa7b47a..d2a232b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -412,7 +412,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"在日出時關閉"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"於<xliff:g id="TIME">%s</xliff:g>開啟"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"直至<xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"調低亮度"</string>
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"調低亮度"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
@@ -446,6 +446,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"此裝置屬於「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"從圖示滑動即可使用手機功能"</string>
<string name="voice_hint" msgid="7476017460191291417">"從圖示滑動即可使用語音助手"</string>
<string name="camera_hint" msgid="4519495795000658637">"從圖示滑動即可使用相機功能"</string>
@@ -625,6 +627,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕按即可設為震動。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕按即可設為靜音。"</string>
+ <string name="volume_ringer_change" msgid="3574969197796055532">"輕按即可變更響鈴模式"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string>
@@ -1038,6 +1041,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"裝置已上鎖"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 含有字母或符號"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"驗證<xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 錯誤"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ca8db2e..396484a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -71,7 +71,7 @@
<string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"目前登入這部裝置的使用者無法開啟無線偵錯功能。如要使用這項功能,請切換到主要使用者。"</string>
<string name="usb_contaminant_title" msgid="894052515034594113">"USB 連接埠已停用"</string>
<string name="usb_contaminant_message" msgid="7730476585174719805">"為了避免液體或灰塵導致你的裝置受損,系統已停用 USB 連接埠,因此目前無法偵測任何配件。\n\n系統會在可繼續使用 USB 連接埠時通知你。"</string>
- <string name="usb_port_enabled" msgid="531823867664717018">"USB 通訊埠已啟用,可偵測充電器和配件"</string>
+ <string name="usb_port_enabled" msgid="531823867664717018">"USB 連接埠已啟用,可偵測充電器和配件"</string>
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"啟用 USB 連接埠"</string>
<string name="learn_more" msgid="4690632085667273811">"瞭解詳情"</string>
<string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"於日出時關閉"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"開啟時間:<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"關閉時間:<xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"調低亮度"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"滑動手機圖示即可啟用"</string>
<string name="voice_hint" msgid="7476017460191291417">"滑動語音小幫手圖示即可啟用"</string>
<string name="camera_hint" msgid="4519495795000658637">"滑動相機圖示即可啟用"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕觸即可設為震動。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕觸即可設為靜音。"</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string>
@@ -1038,6 +1043,7 @@
<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>
+ <string name="controls_tile_locked" msgid="731547768182831938">"裝置已鎖定"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 碼含有字母或符號"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"驗證「<xliff:g id="DEVICE">%s</xliff:g>」"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 碼錯誤"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 371702f..d4e05d0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -412,7 +412,8 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuze kube sekuphumeni kwelanga"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Kuvulwe ngo-<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuze kube ngu-<xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Nciphisa ukukhanya"</string>
+ <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+ <skip />
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"I-NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"I-NFC ikhutshaziwe"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"I-NFC inikwe amandla"</string>
@@ -446,6 +447,8 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Le divayisi ngeye-<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+ <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+ <skip />
<string name="phone_hint" msgid="6682125338461375925">"Swayiphela ifoni kusukela kusithonjana"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swayiphela isilekeleli sezwi kusukela kusithonjana"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swayiphela ikhamela kusukela kusithonjana"</string>
@@ -625,6 +628,8 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Thepha ukuze usethele ekudlidlizeni."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Thepha ukuze uthulise."</string>
+ <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+ <skip />
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"thulisa"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"susa ukuthula"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dlidliza"</string>
@@ -1038,6 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Engeza"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Kuphakanyiswe ngu-<xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Izilawuli zibuyekeziwe"</string>
+ <string name="controls_tile_locked" msgid="731547768182831938">"Idivayisi ikhiyiwe"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Iphinikhodi iqukethe amaletha namasimbui"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Qinisekisa i-<xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Iphinikhodi engalungile"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index acd671c..3bc1c80 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -265,7 +265,6 @@
<color name="control_enabled_cool_foreground">@color/GM2_blue_300</color>
<color name="control_thumbnail_tint">#33000000</color>
<color name="control_thumbnail_shadow_color">@*android:color/black</color>
- <color name="controls_lockscreen_scrim">#AA000000</color>
<!-- Docked misalignment message -->
<color name="misalignment_text_color">#F28B82</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f13fdd3..0893c14 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -91,6 +91,9 @@
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">3</integer>
+ <!-- The number of columns in the Quick Settings customizer -->
+ <integer name="quick_settings_edit_num_columns">@integer/quick_settings_num_columns</integer>
+
<!-- The number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">3</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 89c849a..ea0ea5e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -456,10 +456,12 @@
<dimen name="volume_dialog_panel_transparent_padding">20dp</dimen>
- <dimen name="volume_dialog_stream_padding">8dp</dimen>
+ <dimen name="volume_dialog_stream_padding">12dp</dimen>
<dimen name="volume_dialog_panel_width">64dp</dimen>
+ <dimen name="volume_dialog_panel_width_half">32dp</dimen>
+
<dimen name="volume_dialog_slider_height">116dp</dimen>
<dimen name="volume_dialog_ringer_size">64dp</dimen>
@@ -486,6 +488,13 @@
<dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen>
+ <!-- Size of each item in the ringer selector drawer. -->
+ <dimen name="volume_ringer_drawer_item_size">64dp</dimen>
+ <dimen name="volume_ringer_drawer_item_size_half">32dp</dimen>
+
+ <!-- Size of the icon inside each item in the ringer selector drawer. -->
+ <dimen name="volume_ringer_drawer_icon_size">24dp</dimen>
+
<!-- Gravity for the notification panel -->
<integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
@@ -966,7 +975,7 @@
<dimen name="volume_row_padding_start">4dp</dimen>
<dimen name="volume_row_header_padding_start">16dp</dimen>
<dimen name="volume_row_height">64dp</dimen>
- <dimen name="volume_row_slider_height">48dp</dimen>
+ <dimen name="volume_row_slider_height">192dp</dimen>
<dimen name="volume_row_slider_padding_start">12dp</dimen>
<dimen name="volume_expander_margin_end">2dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 3e16cd4..e551892 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -44,4 +44,6 @@
<bool name="flag_toast_style">false</bool>
<bool name="flag_navigation_bar_overlay">false</bool>
+
+ <bool name="flag_pm_lite">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4b95c16..5f8df5a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -959,7 +959,7 @@
<!-- QuickSettings: Secondary text for when the Dark theme or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
<string name="quick_settings_dark_mode_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
<!-- QuickSettings: Label for the toggle that controls whether Reduce Brightness is enabled. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_reduce_bright_colors_label">Reduce Brightness</string>
+ <string name="quick_settings_reduce_bright_colors_label">Reduce brightness</string>
<!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
<string name="quick_settings_nfc_label">NFC</string>
@@ -1054,6 +1054,9 @@
<!-- Text on keyguard screen and in Quick Settings footer indicating that user's device belongs to their organization. [CHAR LIMIT=40] -->
<string name="do_disclosure_with_name">This device belongs to <xliff:g id="organization_name" example="Foo, Inc.">%s</xliff:g></string>
+ <!-- Text on keyguard screen and in Quick Settings footer indicating that the user's device is provided by the Creditor. [CHAR LIMIT=60] -->
+ <string name="do_financed_disclosure_with_name">This device is provided by <xliff:g id="organization_name" example="Foo, Inc.">%s</xliff:g></string>
+
<!-- Shows when people have clicked on the phone icon [CHAR LIMIT=60] -->
<string name="phone_hint">Swipe from icon for phone</string>
@@ -1558,6 +1561,8 @@
<string name="volume_stream_content_description_vibrate_a11y">%1$s. Tap to set to vibrate.</string>
<string name="volume_stream_content_description_mute_a11y">%1$s. Tap to mute.</string>
+ <string name="volume_ringer_change">Tap to change ringer mode</string>
+
<!-- Hint for accessibility. For example: double tap to mute [CHAR_LIMIT=NONE] -->
<string name="volume_ringer_hint_mute">mute</string>
<!-- Hint for accessibility. For example: double tap to unmute [CHAR_LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 14b376a..2d202fb 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -663,16 +663,16 @@
</style>
<style name="Theme.SystemUI.Dialog.Control.LockScreen" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
- <item name="android:windowAnimationStyle">@style/Animation.Fade</item>
+ <item name="android:windowAnimationStyle">@style/Animation.ControlDialog</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowIsFloating">false</item>
- <item name="android:windowBackground">@color/controls_lockscreen_scrim</item>
+ <item name="android:windowBackground">@null</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
- <style name="Animation.Fade">
- <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
- <item name="android:windowExitAnimation">@android:anim/fade_out</item>
+ <style name="Animation.ControlDialog">
+ <item name="android:windowEnterAnimation">@*android:anim/dialog_enter</item>
+ <item name="android:windowExitAnimation">@*android:anim/dialog_exit</item>
</style>
<style name="Control" />
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d9a1eb6..a4054be 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -305,6 +305,7 @@
private boolean mLogoutEnabled;
// cached value to avoid IPCs
private boolean mIsUdfpsEnrolled;
+ private boolean mKeyguardQsUserSwitchEnabled;
// If the user long pressed the lock icon, disabling face auth for the current session.
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -1916,7 +1917,7 @@
return isFaceAuthEnabledForUser(KeyguardUpdateMonitor.getCurrentUser())
&& !isUdfpsEnrolled();
}
- return true;
+ return !isKeyguardQsUserSwitchEnabled();
}
/**
@@ -1926,6 +1927,17 @@
return mIsUdfpsEnrolled;
}
+ /**
+ * @return true if the keyguard qs user switcher shortcut is enabled
+ */
+ public boolean isKeyguardQsUserSwitchEnabled() {
+ return mKeyguardQsUserSwitchEnabled;
+ }
+
+ public void setKeyguardQsUserSwitchEnabled(boolean enabled) {
+ mKeyguardQsUserSwitchEnabled = enabled;
+ }
+
private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 8cb1bc4..5db3349 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -69,7 +69,9 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mAnimator != null) mAnimator.start();
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ if (mAnimator != null) mAnimator.start();
+ }
return super.onTouchEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index a4a781d..e6a9d4f 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -160,10 +160,9 @@
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
doHapticKeyClick();
+ if (mAnimator != null) mAnimator.start();
}
- if (mAnimator != null) mAnimator.start();
-
return super.onTouchEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 19520df..9d00262 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -115,7 +115,8 @@
.setShellCommandHandler(mWMComponent.getShellCommandHandler())
.setAppPairs(mWMComponent.getAppPairs())
.setTaskViewFactory(mWMComponent.getTaskViewFactory())
- .setTransitions(mWMComponent.getTransitions());
+ .setTransitions(mWMComponent.getTransitions())
+ .setStartingSurface(mWMComponent.getStartingSurface());
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
// is separating this logic into newly creating SystemUITestsFactory.
@@ -129,7 +130,8 @@
.setShellCommandHandler(Optional.ofNullable(null))
.setAppPairs(Optional.ofNullable(null))
.setTaskViewFactory(Optional.ofNullable(null))
- .setTransitions(Transitions.createEmptyForTesting());
+ .setTransitions(Transitions.createEmptyForTesting())
+ .setStartingSurface(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
if (initializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 9686c91f..2040347 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -16,8 +16,8 @@
package com.android.systemui.appops;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
import android.Manifest;
@@ -40,6 +40,7 @@
import androidx.annotation.WorkerThread;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
@@ -78,6 +79,7 @@
private static final boolean DEBUG = false;
private final BroadcastDispatcher mDispatcher;
+ private final Context mContext;
private final AppOpsManager mAppOps;
private final AudioManager mAudioManager;
private final LocationManager mLocationManager;
@@ -137,10 +139,11 @@
mAudioManager = audioManager;
mSensorPrivacyController = sensorPrivacyController;
mMicMuted = audioManager.isMicrophoneMute()
- || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
- mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+ || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA);
mLocationManager = context.getSystemService(LocationManager.class);
mPackageManager = context.getPackageManager();
+ mContext = context;
dumpManager.registerDumpable(TAG, this);
}
@@ -159,8 +162,8 @@
mSensorPrivacyController.addCallback(this);
mMicMuted = mAudioManager.isMicrophoneMute()
- || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
- mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+ || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
+ mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA);
mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
mAudioManager.getActiveRecordingConfigurations()));
@@ -357,6 +360,15 @@
return mLocationProviderPackages.contains(packageName);
}
+ private boolean isSpeechRecognizerUsage(int opCode, String packageName) {
+ if (AppOpsManager.OP_RECORD_AUDIO != opCode) {
+ return false;
+ }
+
+ return packageName.equals(
+ mContext.getString(R.string.config_systemSpeechRecognizer));
+ }
+
// TODO ntmyren: remove after teamfood is finished
private boolean shouldShowAppPredictor(String pkgName) {
if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "permissions_hub_2_enabled",
@@ -388,7 +400,8 @@
}
// TODO ntmyren: Replace this with more robust check if this moves beyond teamfood
if ((appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName))
- || shouldShowAppPredictor(packageName)) {
+ || shouldShowAppPredictor(packageName)
+ || isSpeechRecognizerUsage(appOpCode, packageName)) {
return true;
}
@@ -583,16 +596,16 @@
@Override
public void onReceive(Context context, Intent intent) {
mMicMuted = mAudioManager.isMicrophoneMute()
- || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+ || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
updateSensorDisabledStatus();
}
@Override
public void onSensorBlockedChanged(int sensor, boolean blocked) {
mBGHandler.post(() -> {
- if (sensor == INDIVIDUAL_SENSOR_CAMERA) {
+ if (sensor == CAMERA) {
mCameraDisabled = blocked;
- } else if (sensor == INDIVIDUAL_SENSOR_MICROPHONE) {
+ } else if (sensor == MICROPHONE) {
mMicMuted = mAudioManager.isMicrophoneMute() || blocked;
}
updateSensorDisabledStatus();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 6451ad9..71fba33 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -68,6 +68,7 @@
private final Context mContext;
private final FingerprintManager mFingerprintManager;
+ @NonNull private final LayoutInflater mInflater;
private final WindowManager mWindowManager;
private final DelayableExecutor mFgExecutor;
private final StatusBarStateController mStatusBarStateController;
@@ -75,10 +76,8 @@
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
private final WindowManager.LayoutParams mCoreLayoutParams;
- private final UdfpsView mView;
- // Indicates whether the overlay is currently showing. Even if it has been requested, it might
- // not be showing.
- private boolean mIsOverlayShowing;
+
+ @Nullable private UdfpsView mView;
// Indicates whether the overlay has been requested.
private boolean mIsOverlayRequested;
// Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
@@ -111,20 +110,48 @@
@Override
public void onEnrollmentProgress(int sensorId, int remaining) {
+ if (mView == null) {
+ return;
+ }
mView.onEnrollmentProgress(remaining);
}
@Override
public void onEnrollmentHelp(int sensorId) {
+ if (mView == null) {
+ return;
+ }
mView.onEnrollmentHelp();
}
@Override
public void setDebugMessage(int sensorId, String message) {
+ if (mView == null) {
+ return;
+ }
mView.setDebugMessage(message);
}
}
+ @VisibleForTesting
+ final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
+ (expansion, expanded) -> {
+ if (mView != null) {
+ mView.onExpansionChanged(expansion, expanded);
+ }
+ };
+
+ @VisibleForTesting
+ final StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ if (mView != null) {
+ mView.onStateChanged(newState);
+ }
+ }
+ };
+
@SuppressLint("ClickableViewAccessibility")
private final UdfpsView.OnTouchListener mOnTouchListener = (v, event) -> {
UdfpsView view = (UdfpsView) v;
@@ -157,13 +184,14 @@
@Inject
public UdfpsController(@NonNull Context context,
@Main Resources resources,
- LayoutInflater inflater,
+ @NonNull LayoutInflater inflater,
@Nullable FingerprintManager fingerprintManager,
WindowManager windowManager,
@NonNull StatusBarStateController statusBarStateController,
@Main DelayableExecutor fgExecutor,
@Nullable StatusBar statusBar) {
mContext = context;
+ mInflater = inflater;
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
// fingerprint manager should never be null.
mFingerprintManager = checkNotNull(fingerprintManager);
@@ -189,15 +217,10 @@
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
- mView = (UdfpsView) inflater.inflate(R.layout.udfps_view, null, false);
- mView.setSensorProperties(mSensorProps);
- mView.setHbmCallback(this);
-
- statusBar.addExpansionChangedListener(mView);
- statusBarStateController.addCallback(mView);
+ statusBar.addExpansionChangedListener(mStatusBarExpansionListener);
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
- mIsOverlayShowing = false;
}
@Nullable
@@ -220,7 +243,13 @@
* @return where the UDFPS exists on the screen in pixels.
*/
public RectF getSensorLocation() {
- return mView.getSensorRect();
+ // This is currently used to calculate the amount of space available for notifications
+ // on lockscreen. Keyguard is only shown in portrait mode for now, so this will need to
+ // be updated if that ever changes.
+ return new RectF(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationX + mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
}
private void showOverlay(int reason) {
@@ -298,14 +327,18 @@
private void showUdfpsOverlay(int reason) {
mFgExecutor.execute(() -> {
- if (!mIsOverlayShowing) {
+ if (mView == null) {
try {
Log.v(TAG, "showUdfpsOverlay | adding window");
+
+ mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
+ mView.setSensorProperties(mSensorProps);
+ mView.setHbmCallback(this);
+
final UdfpsAnimation animation = getUdfpsAnimationForReason(reason);
mView.setExtras(animation, mEnrollHelper);
mWindowManager.addView(mView, computeLayoutParams(animation));
mView.setOnTouchListener(mOnTouchListener);
- mIsOverlayShowing = true;
} catch (RuntimeException e) {
Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
}
@@ -334,14 +367,12 @@
private void hideUdfpsOverlay() {
mFgExecutor.execute(() -> {
- if (mIsOverlayShowing) {
+ if (mView != null) {
Log.v(TAG, "hideUdfpsOverlay | removing window");
- mView.setExtras(null, null);
- mView.setOnTouchListener(null);
// Reset the controller back to its starting state.
onFingerUp();
mWindowManager.removeView(mView);
- mIsOverlayShowing = false;
+ mView = null;
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
}
@@ -388,12 +419,20 @@
// This method can be called from the UI thread.
private void onFingerDown(int x, int y, float minor, float major) {
+ if (mView == null) {
+ Log.w(TAG, "Null view in onFingerDown");
+ return;
+ }
mView.startIllumination(() ->
mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major));
}
// This method can be called from the UI thread.
private void onFingerUp() {
+ if (mView == null) {
+ Log.w(TAG, "Null view in onFingerUp");
+ return;
+ }
mFingerprintManager.onPointerUp(mSensorProps.sensorId);
mView.stopIllumination();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 6ffecdb..3997943 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -136,17 +136,13 @@
}
@Override
- public void onExpandedChanged(boolean isExpanded) {
- mNotificationShadeExpanded = isExpanded;
- }
-
- @Override
public void onStateChanged(int newState) {
mStatusBarState = newState;
}
@Override
public void onExpansionChanged(float expansion, boolean expanded) {
+ mNotificationShadeExpanded = expanded;
mAnimationView.onExpansionChanged(expansion, expanded);
}
@@ -192,10 +188,6 @@
}
}
- RectF getSensorRect() {
- return new RectF(mSensorRect);
- }
-
void setDebugMessage(String message) {
mDebugMessage = message;
postInvalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
index cad166d..1ea1d97 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
@@ -41,7 +41,7 @@
object ControlsAnimations {
- private const val ALPHA_EXIT_DURATION = 167L
+ private const val ALPHA_EXIT_DURATION = 183L
private const val ALPHA_ENTER_DELAY = ALPHA_EXIT_DURATION
private const val ALPHA_ENTER_DURATION = 350L - ALPHA_ENTER_DELAY
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 1c2f17c..2d647a9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -313,6 +313,10 @@
setOnClickListener {
val i = Intent().apply {
component = ComponentName(context, ControlsProviderSelectorActivity::class.java)
+ putExtra(
+ ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
+ backToGlobalActions
+ )
}
if (doneButton.isEnabled) {
// The user has made changes
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 0814774..d5e41d0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -32,6 +32,8 @@
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.controls.ui.ControlsDialog
+import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.globalactions.GlobalActionsComponent
@@ -49,13 +51,15 @@
private val listingController: ControlsListingController,
private val controlsController: ControlsController,
private val globalActionsComponent: GlobalActionsComponent,
- broadcastDispatcher: BroadcastDispatcher
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val uiController: ControlsUiController
) : LifecycleActivity() {
companion object {
private const val TAG = "ControlsProviderSelectorActivity"
}
+ private var backToGlobalActions = true
private lateinit var recyclerView: RecyclerView
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
private val startingUser = listingController.currentUserId
@@ -101,10 +105,19 @@
}
}
requireViewById<View>(R.id.done).visibility = View.GONE
+
+ backToGlobalActions = intent.getBooleanExtra(
+ ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
+ true
+ )
}
override fun onBackPressed() {
- globalActionsComponent.handleShowGlobalActionsMenu()
+ if (backToGlobalActions) {
+ globalActionsComponent.handleShowGlobalActionsMenu()
+ } else {
+ ControlsDialog(applicationContext, broadcastDispatcher).show(uiController)
+ }
animateExitAndFinish()
}
@@ -152,8 +165,13 @@
listingController.getAppLabel(it))
putExtra(Intent.EXTRA_COMPONENT_NAME, it)
putExtra(ControlsFavoritingActivity.EXTRA_FROM_PROVIDER_SELECTOR, true)
+ putExtra(
+ ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
+ backToGlobalActions
+ )
}
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
+ animateExitAndFinish()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index ffb8446..8f79de5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -33,6 +33,7 @@
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -88,6 +89,9 @@
@BindsInstance
Builder setTransitions(RemoteTransitions t);
+ @BindsInstance
+ Builder setStartingSurface(Optional<StartingSurface> s);
+
SysUIComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index f3726a3..1b77d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -32,6 +32,7 @@
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -98,4 +99,7 @@
@WMSingleton
RemoteTransitions getTransitions();
+
+ @WMSingleton
+ Optional<StartingSurface> getStartingSurface();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index d4678f3..127128d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -103,6 +103,11 @@
*/
public void updateIndication(@IndicationType int type, KeyguardIndication newIndication,
boolean showImmediately) {
+ if (type == INDICATION_TYPE_NOW_PLAYING
+ || type == INDICATION_TYPE_REVERSE_CHARGING) {
+ // temporarily don't show here, instead use AmbientContainer b/181049781
+ return;
+ }
final boolean hasPreviousIndication = mIndicationMessages.get(type) != null;
final boolean hasNewIndication = newIndication != null;
if (!hasNewIndication) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java
index b1c85b5..8ff7b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java
@@ -84,19 +84,14 @@
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
mClickableChildren.clear();
mAttachedChildren.clear();
mTouchableRegions.clear();
addClickableChildren(this);
- cacheClosestChildLocations();
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
getLocationInWindow(mOffset);
+ cacheClosestChildLocations();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 2f9b17a..2ea8657 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -19,8 +19,6 @@
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
-import static com.android.systemui.people.PeopleSpaceUtils.getUserHandle;
-
import android.app.Activity;
import android.app.INotificationManager;
import android.app.people.IPeopleManager;
@@ -155,7 +153,7 @@
if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId());
mLauncherApps.cacheShortcuts(tile.getPackageName(),
Collections.singletonList(tile.getId()),
- getUserHandle(tile), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
+ tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
} catch (Exception e) {
Log.w(TAG, "Exception caching shortcut:" + e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
index 9ae7847..6f89332 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
@@ -21,7 +21,6 @@
import android.content.pm.LauncherApps;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
-import android.os.UserHandle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -82,7 +81,7 @@
public void setOnClickListener(LauncherApps launcherApps, PeopleSpaceTile tile) {
mTileView.setOnClickListener(v ->
launcherApps.startShortcut(tile.getPackageName(), tile.getId(), null, null,
- UserHandle.getUserHandleForUid(tile.getUid())));
+ tile.getUserHandle()));
}
/** Sets the click listener of the tile directly. */
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 5dda23e..41080af 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -55,7 +55,6 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
@@ -160,7 +159,6 @@
List<ConversationChannelWrapper> conversations =
notificationManager.getConversations(
false).getList();
-
// Add priority conversations to tiles list.
Stream<ShortcutInfo> priorityConversations = conversations.stream()
.filter(c -> c.getNotificationChannel() != null
@@ -252,7 +250,11 @@
}
// If tile is null, we need to retrieve from persisted storage.
- if (DEBUG) Log.d(TAG, "Retrieving from storage after reboots");
+ if (DEBUG) {
+ Log.d(TAG,
+ "Retrieving from storage after reboots: " + shortcutId + " user: " + userId
+ + " pkg: " + pkg);
+ }
LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
ConversationChannel channel = peopleManager.getConversation(pkg, userId, shortcutId);
if (channel == null) {
@@ -384,7 +386,7 @@
PeopleSpaceTile tile, Map<String, NotificationEntry> visibleNotifications) {
String shortcutId = tile.getId();
String packageName = tile.getPackageName();
- int userId = UserHandle.getUserHandleForUid(tile.getUid()).getIdentifier();
+ int userId = getUserId(tile);
String key = getKey(shortcutId, packageName, userId);
if (!visibleNotifications.containsKey(key)) {
if (DEBUG) Log.d(TAG, "No existing notifications for key:" + key);
@@ -641,7 +643,8 @@
activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
activityIntent.putExtra(
PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
- activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
+ activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE,
+ tile.getUserHandle());
views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
context,
appWidgetId,
@@ -788,7 +791,6 @@
Log.i(TAG, "ConversationChannel is null");
return null;
}
-
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(channel, launcherApps).build();
if (!PeopleSpaceUtils.shouldKeepConversation(tile)) {
Log.i(TAG, "PeopleSpaceTile is not valid");
@@ -1069,11 +1071,6 @@
/** Returns the userId associated with a {@link PeopleSpaceTile} */
public static int getUserId(PeopleSpaceTile tile) {
- return getUserHandle(tile).getIdentifier();
- }
-
- /** Returns the {@link UserHandle} associated with a {@link PeopleSpaceTile} */
- public static UserHandle getUserHandle(PeopleSpaceTile tile) {
- return UserHandle.getUserHandleForUid(tile.getUid());
+ return tile.getUserHandle().getIdentifier();
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
index 358f311..13e30f9 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
@@ -41,7 +41,8 @@
Intent intent = getIntent();
String tileId = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID);
String packageName = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME);
- int uid = intent.getIntExtra(PeopleSpaceWidgetProvider.EXTRA_UID, 0);
+ UserHandle userHandle = intent.getParcelableExtra(
+ PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE);
if (tileId != null && !tileId.isEmpty()) {
if (DEBUG) {
@@ -52,7 +53,7 @@
LauncherApps launcherApps =
getApplicationContext().getSystemService(LauncherApps.class);
launcherApps.startShortcut(
- packageName, tileId, null, null, UserHandle.getUserHandleForUid(uid));
+ packageName, tileId, null, null, userHandle);
} catch (Exception e) {
Log.e(TAG, "Exception starting shortcut:" + e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
index 3d1055f..90baf56 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
@@ -48,7 +48,7 @@
public static final String EXTRA_TILE_ID = "extra_tile_id";
public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
- public static final String EXTRA_UID = "extra_uid";
+ public static final String EXTRA_USER_HANDLE = "extra_user_handle";
public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
index 80794cb..0503522 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
@@ -123,7 +123,8 @@
fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
fillInIntent.putExtra(
PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
- fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
+ fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE,
+ tile.getUserHandle());
personView.setOnClickFillInIntent(R.id.item, fillInIntent);
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve shortcut information", e);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index eaf2123..fcb56a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -71,7 +71,6 @@
private int mMinRows = 1;
private int mMaxColumns = TileLayout.NO_MAX_COLUMNS;
- private boolean mShowLabels = true;
private final boolean mSideLabels;
public PagedTileLayout(Context context, AttributeSet attrs) {
@@ -91,16 +90,6 @@
}
private int mLastMaxHeight = -1;
- @Override
- public void setShowLabels(boolean show) {
- mShowLabels = show;
- for (TileLayout p : mPages) {
- p.setShowLabels(show);
- }
- mDistributeTiles = true;
- requestLayout();
- }
-
public void saveInstanceState(Bundle outState) {
outState.putInt(CURRENT_PAGE, getCurrentItem());
}
@@ -239,7 +228,6 @@
: R.layout.qs_paged_page, this, false);
page.setMinRows(mMinRows);
page.setMaxColumns(mMaxColumns);
- page.setShowLabels(mShowLabels);
return page;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index c8edaec..fe76668 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -29,7 +29,6 @@
import com.android.systemui.qs.TouchAnimator.Builder;
import com.android.systemui.qs.TouchAnimator.Listener;
import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.qs.tileimpl.QSTileBaseView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -56,7 +55,8 @@
private final ArrayList<View> mAllViews = new ArrayList<>();
/**
* List of {@link View}s representing Quick Settings that are being animated from the quick QS
- * position to the normal QS panel.
+ * position to the normal QS panel. These views will only show once the animation is complete,
+ * to prevent overlapping of semi transparent views
*/
private final ArrayList<View> mQuickQsViews = new ArrayList<>();
private final QuickQSPanel mQuickQsPanel;
@@ -233,7 +233,6 @@
// Quick tiles.
QSTileView quickTileView = mQuickQSPanelController.getTileView(tile);
if (quickTileView == null) continue;
- View qqsBgCircle = ((QSTileBaseView) quickTileView).getBgCircle();
getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
getRelativePosition(loc2, tileIcon, view);
@@ -255,11 +254,6 @@
translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
- if (mFeatureFlags.isQSLabelsEnabled()) {
- firstPageBuilder.addFloat(qqsBgCircle, "alpha", 1, 1, 0);
- mAllViews.add(qqsBgCircle);
- }
-
} else { // These tiles disappear when expanding
firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0);
translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
@@ -271,7 +265,11 @@
translationX);
}
- mQuickQsViews.add(tileView.getIconWithBackground());
+ if (mFeatureFlags.isQSLabelsEnabled()) {
+ mQuickQsViews.add(tileView);
+ } else {
+ mQuickQsViews.add(tileView.getIconWithBackground());
+ }
mAllViews.add(tileView.getIcon());
mAllViews.add(quickTileView);
} else if (mFullRows && isIconInAnimatedRow(count)) {
@@ -362,7 +360,7 @@
if(view == parent || view == null) return;
// Ignore tile pages as they can have some offset we don't want to take into account in
// RTL.
- if (!(view instanceof PagedTileLayout.TilePage || view instanceof SideLabelTileLayout)) {
+ if (!isAPage(view)) {
loc1[0] += view.getLeft();
loc1[1] += view.getTop();
}
@@ -374,6 +372,16 @@
getRelativePositionInt(loc1, (View) view.getParent(), parent);
}
+ // 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;
+ }
+
public void setPosition(float position) {
if (mNeedsAnimatorUpdate) {
updateAnimators();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 16e5196..2bea72c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs;
+import static com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED;
+
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
@@ -41,6 +43,7 @@
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* Controller for {@link QSFooterView}.
@@ -63,6 +66,8 @@
private final View mEdit;
private final MultiUserSwitch mMultiUserSwitch;
private final PageIndicator mPageIndicator;
+ private final View mPowerMenuLite;
+ private final boolean mShowPMLiteButton;
private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
new UserInfoController.OnUserInfoChangedListener() {
@@ -123,7 +128,8 @@
DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
QSPanelController qsPanelController, QSDetailDisplayer qsDetailDisplayer,
QuickQSPanelController quickQSPanelController,
- TunerService tunerService, MetricsLogger metricsLogger) {
+ TunerService tunerService, MetricsLogger metricsLogger,
+ @Named(PM_LITE_ENABLED) boolean showPMLiteButton) {
super(view);
mUserManager = userManager;
mUserInfoController = userInfoController;
@@ -141,10 +147,15 @@
mEdit = mView.findViewById(android.R.id.edit);
mMultiUserSwitch = mView.findViewById(R.id.multi_user_switch);
mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
+ mPowerMenuLite = mView.findViewById(R.id.pm_lite);
+ mShowPMLiteButton = showPMLiteButton;
}
@Override
protected void onViewAttached() {
+ if (mShowPMLiteButton) {
+ mPowerMenuLite.setVisibility(View.VISIBLE);
+ }
mView.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
mView.updateAnimator(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 91ae571..7657dce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -112,7 +112,7 @@
private int mMediaTotalBottomMargin;
private int mFooterMarginStartHorizontal;
private Consumer<Boolean> mMediaVisibilityChangedListener;
- private boolean mSideLabels;
+ protected boolean mSideLabels;
public QSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -201,16 +201,20 @@
mFooterPageIndicator.setNumPages(((PagedTileLayout) mTileLayout).getNumPages());
}
- // Allow the UI to be as big as it want's to, we're in a scroll view
- int newHeight = 10000;
- int availableHeight = MeasureSpec.getSize(heightMeasureSpec);
- int excessHeight = newHeight - availableHeight;
- // Measure with EXACTLY. That way, The content will only use excess height and will
- // be measured last, after other views and padding is accounted for. This only
- // works because our Layouts in here remeasure themselves with the exact content
- // height.
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
- ((PagedTileLayout) mTileLayout).setExcessHeight(excessHeight);
+ // In landscape, mTileLayout's parent is not the panel but a view that contains the
+ // tile layout and the media controls.
+ if (((View) mTileLayout).getParent() == this) {
+ // Allow the UI to be as big as it want's to, we're in a scroll view
+ int newHeight = 10000;
+ int availableHeight = MeasureSpec.getSize(heightMeasureSpec);
+ int excessHeight = newHeight - availableHeight;
+ // Measure with EXACTLY. That way, The content will only use excess height and will
+ // be measured last, after other views and padding is accounted for. This only
+ // works because our Layouts in here remeasure themselves with the exact content
+ // height.
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
+ ((PagedTileLayout) mTileLayout).setExcessHeight(excessHeight);
+ }
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -758,7 +762,7 @@
// Let's use 3 columns to match the current layout
int columns;
if (mSideLabels) {
- columns = horizontal ? 1 : 2;
+ columns = horizontal ? 2 : 4;
} else {
columns = horizontal ? 3 : TileLayout.NO_MAX_COLUMNS;
}
@@ -843,8 +847,6 @@
default void setExpansion(float expansion) {}
int getNumVisibleTiles();
-
- default void setShowLabels(boolean show) {}
}
interface OnConfigurationChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index fcb35e2..eda1abb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -18,7 +18,6 @@
import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
import static com.android.systemui.qs.QSPanel.QS_SHOW_BRIGHTNESS;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
import android.annotation.NonNull;
@@ -66,7 +65,6 @@
private BrightnessMirrorController mBrightnessMirrorController;
private boolean mGridContentVisible = true;
- private boolean mQsLabelsFlag;
private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
new QSPanel.OnConfigurationChangedListener() {
@@ -93,7 +91,6 @@
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
BrightnessSlider.Factory brightnessSliderFactory,
- @Named(QS_LABELS_FLAG) boolean qsLabelsFlag,
FeatureFlags featureFlags) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
metricsLogger, uiEventLogger, qsLogger, dumpManager, featureFlags);
@@ -108,9 +105,6 @@
mView.setBrightnessView(mBrightnessSlider.getRootView());
mBrightnessController = brightnessControllerFactory.create(mBrightnessSlider);
-
- mQsLabelsFlag = qsLabelsFlag;
- mSideLabels = qsLabelsFlag;
}
@Override
@@ -130,7 +124,6 @@
updateMediaDisappearParameters();
mTunerService.addTunable(mView, QS_SHOW_BRIGHTNESS);
- mTunerService.addTunable(mTunable, QS_REMOVE_LABELS);
mView.updateResources();
if (mView.isListening()) {
refreshAllTiles();
@@ -144,13 +137,6 @@
}
@Override
- boolean switchTileLayout(boolean force) {
- boolean result = super.switchTileLayout(force);
- getTileLayout().setShowLabels(mShowLabels);
- return result;
- }
-
- @Override
protected QSTileRevealController createTileRevealController() {
return mQsTileRevealControllerFactory.create(
this, (PagedTileLayout) mView.createRegularTileLayout());
@@ -158,7 +144,6 @@
@Override
protected void onViewDetached() {
- mTunerService.removeTunable(mTunable);
mTunerService.removeTunable(mView);
mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
if (mBrightnessMirrorController != null) {
@@ -324,22 +309,5 @@
public boolean isExpanded() {
return mView.isExpanded();
}
-
- private TunerService.Tunable mTunable = new TunerService.Tunable() {
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (QS_REMOVE_LABELS.equals(key)) {
- if (!mQsLabelsFlag) return;
- boolean newShowLabels = newValue == null || "0".equals(newValue);
- if (mShowLabels == newShowLabels) return;
- mShowLabels = newShowLabels;
- for (TileRecord t : mRecords) {
- t.tileView.setShowLabels(mShowLabels);
- }
- getTileLayout().setShowLabels(mShowLabels);
- mView.requestLayout();
- }
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 9426e71..8ab1743 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -75,7 +75,7 @@
private final QSHost.Callback mQSHostCallback = this::setTiles;
protected boolean mShowLabels = true;
- protected boolean mSideLabels;
+ protected boolean mQSLabelFlag;
private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
new QSPanel.OnConfigurationChangedListener() {
@@ -118,11 +118,12 @@
mQSLogger = qsLogger;
mDumpManager = dumpManager;
mFeatureFlags = featureFlags;
+ mQSLabelFlag = featureFlags.isQSLabelsEnabled();
}
@Override
protected void onInit() {
- mView.initialize(mSideLabels);
+ mView.initialize(mQSLabelFlag);
mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), "");
}
@@ -197,7 +198,6 @@
final TileRecord r = new TileRecord();
r.tile = tile;
r.tileView = mHost.createTileView(tile, collapsedView);
- r.tileView.setShowLabels(mShowLabels);
mView.addTile(r);
mRecords.add(r);
mCachedSpecs = getTilesSpecs();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index a29ac3b..9b66b59 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -69,12 +69,22 @@
@Override
public TileLayout createRegularTileLayout() {
- return new QuickQSPanel.HeaderTileLayout(mContext);
+ if (mSideLabels) {
+ return new QQSSideLabelTileLayout(mContext);
+ } else {
+ return new QuickQSPanel.HeaderTileLayout(mContext);
+ }
}
@Override
protected QSTileLayout createHorizontalTileLayout() {
- return new DoubleLineTileLayout(mContext);
+ if (mSideLabels) {
+ TileLayout t = createRegularTileLayout();
+ t.setMaxColumns(2);
+ return t;
+ } else {
+ return new DoubleLineTileLayout(mContext);
+ }
}
@Override
@@ -331,4 +341,38 @@
}
}
}
+
+ static class QQSSideLabelTileLayout extends SideLabelTileLayout {
+ QQSSideLabelTileLayout(Context context) {
+ super(context, null);
+ setClipChildren(false);
+ setClipToPadding(false);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT);
+ lp.gravity = Gravity.CENTER_HORIZONTAL;
+ setLayoutParams(lp);
+ setMaxColumns(4);
+ }
+
+ @Override
+ public boolean updateResources() {
+ boolean b = super.updateResources();
+ mMaxAllowedRows = 2;
+ return b;
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateResources();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Make sure to always use the correct number of rows. As it's determined by the
+ // columns, just use as many as needed.
+ updateMaxRows(10000, mRecords.size());
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 383e932..671f8f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -17,7 +17,6 @@
package com.android.systemui.qs;
import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
import com.android.internal.logging.MetricsLogger;
@@ -42,8 +41,6 @@
@QSScope
public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> {
- private boolean mUseSideLabels;
-
private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
newConfig -> {
int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
@@ -58,12 +55,10 @@
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
@Named(QUICK_QS_PANEL) MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
- DumpManager dumpManager, @Named(QS_LABELS_FLAG) boolean qsLabelsFlag,
- FeatureFlags featureFlags
+ DumpManager dumpManager, FeatureFlags featureFlags
) {
super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
uiEventLogger, qsLogger, dumpManager, featureFlags);
- mUseSideLabels = qsLabelsFlag;
}
@Override
@@ -104,19 +99,7 @@
break;
}
}
- if (mUseSideLabels) {
- List<QSTile> newTiles = new ArrayList<>();
- for (int i = 0; i < tiles.size(); i += 2) {
- newTiles.add(tiles.get(i));
- }
- for (int i = 1; i < tiles.size(); i += 2) {
- newTiles.add(tiles.get(i));
- }
- super.setTiles(newTiles, true);
-
- } else {
- super.setTiles(tiles, true);
- }
+ super.setTiles(tiles, !mQSLabelFlag);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index 74a7ac1..c3cc3af 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -20,11 +20,13 @@
import android.util.AttributeSet
import com.android.systemui.R
-open class SideLabelTileLayout(context: Context, attrs: AttributeSet) : TileLayout(context, attrs) {
+open class SideLabelTileLayout(
+ context: Context,
+ attrs: AttributeSet?
+) : TileLayout(context, attrs) {
override fun updateResources(): Boolean {
return super.updateResources().also {
- mResourceColumns = 2
mMaxAllowedRows = 4
mCellMarginHorizontal = (mCellMarginHorizontal * 1.2).toInt()
mCellMarginVertical = mCellMarginHorizontal
@@ -32,8 +34,6 @@
}
}
- override fun setShowLabels(show: Boolean) { }
-
override fun isFull(): Boolean {
return mRecords.size >= maxTiles()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index d559e07..c1ce4a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -36,7 +36,6 @@
private int mCellMarginTop;
protected boolean mListening;
protected int mMaxAllowedRows = 3;
- private boolean mShowLabels = true;
// Prototyping with less rows
private final boolean mLessRows;
@@ -57,12 +56,6 @@
}
@Override
- public void setShowLabels(boolean show) {
- mShowLabels = show;
- updateResources();
- }
-
- @Override
public int getOffsetTop(TileRecord tile) {
return getTop();
}
@@ -124,15 +117,13 @@
public boolean updateResources() {
final Resources res = mContext.getResources();
mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
+ updateColumns();
mMaxCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
- if (!mShowLabels && mCellMarginVertical == 0) {
- mCellMarginVertical = mCellMarginHorizontal;
- }
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
- if (mLessRows && mShowLabels) mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1);
+ if (mLessRows) mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1);
if (updateColumns()) {
requestLayout();
return true;
@@ -193,9 +184,8 @@
+ mCellMarginVertical;
final int previousRows = mRows;
mRows = availableHeight / (getCellHeight() + mCellMarginVertical);
- final int minRows = mShowLabels ? mMinRows : mMinRows + 1;
- if (mRows < minRows) {
- mRows = minRows;
+ if (mRows < mMinRows) {
+ mRows = mMinRows;
} else if (mRows >= mMaxAllowedRows) {
mRows = mMaxAllowedRows;
}
@@ -215,7 +205,7 @@
}
protected int getCellHeight() {
- return mShowLabels ? mMaxCellHeight : mMaxCellHeight / 2;
+ return mMaxCellHeight;
}
protected void layoutTileRecords(int numRecords) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index a567f51..0dc0b30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -42,6 +42,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import java.util.function.Consumer;
@@ -74,30 +75,25 @@
private final NetworkController.SignalCallback mSignalCallback =
new NetworkController.SignalCallback() {
@Override
- public void setMobileDataIndicators(NetworkController.IconState statusIcon,
- NetworkController.IconState qsIcon, int statusType, int qsType,
- boolean activityIn, boolean activityOut,
- CharSequence typeContentDescription,
- CharSequence typeContentDescriptionHtml, CharSequence description,
- boolean isWide, int subId, boolean roaming, boolean showTriangle) {
+ public void setMobileDataIndicators(MobileDataIndicators indicators) {
if (mProviderModel) {
return;
}
- int slotIndex = getSlotIndex(subId);
+ int slotIndex = getSlotIndex(indicators.subId);
if (slotIndex >= SIM_SLOTS) {
Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
return;
}
if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
- Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
+ Log.e(TAG, "Invalid SIM slot index for subscription: " + indicators.subId);
return;
}
mInfos[slotIndex] = new CellSignalState(
- statusIcon.visible,
- statusIcon.icon,
- statusIcon.contentDescription,
- typeContentDescription.toString(),
- roaming
+ indicators.statusIcon.visible,
+ indicators.statusIcon.icon,
+ indicators.statusIcon.contentDescription,
+ indicators.typeContentDescription.toString(),
+ indicators.roaming
);
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
}
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 9fe949b..dce081f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -25,7 +25,6 @@
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toolbar;
@@ -48,7 +47,6 @@
public class QSCustomizer extends LinearLayout {
static final int MENU_RESET = Menu.FIRST;
- static final int MENU_REMOVE_LABELS = Menu.FIRST + 1;
static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
private final QSDetailClipper mClipper;
@@ -77,10 +75,6 @@
toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
mContext.getString(com.android.internal.R.string.reset));
- // Prototype menu item
- toolbar.getMenu()
- .add(Menu.NONE, MENU_REMOVE_LABELS, Menu.NONE, R.string.qs_remove_labels)
- .setCheckable(true);
toolbar.setTitle(R.string.qs_edit);
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
@@ -89,11 +83,6 @@
mRecyclerView.setItemAnimator(animator);
}
- MenuItem getRemoveItem() {
- return ((Toolbar) findViewById(com.android.internal.R.id.action_bar))
- .getMenu().findItem(MENU_REMOVE_LABELS);
- }
-
void updateResources() {
LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
lp.height = mContext.getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
index d4bab21..f56a2bb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -17,9 +17,7 @@
package com.android.systemui.qs.customize;
import static com.android.systemui.qs.customize.QSCustomizer.EXTRA_QS_CUSTOMIZING;
-import static com.android.systemui.qs.customize.QSCustomizer.MENU_REMOVE_LABELS;
import static com.android.systemui.qs.customize.QSCustomizer.MENU_RESET;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -38,7 +36,6 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSFragment;
-import com.android.systemui.qs.QSPanelController;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -46,14 +43,12 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.ViewController;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
-import javax.inject.Named;
/** {@link ViewController} for {@link QSCustomizer}. */
@QSScope
@@ -67,8 +62,6 @@
private final ConfigurationController mConfigurationController;
private final UiEventLogger mUiEventLogger;
private final Toolbar mToolbar;
- private final TunerService mTunerService;
- private final boolean mQsLabelsFlag;
private final OnMenuItemClickListener mOnMenuItemClickListener = new OnMenuItemClickListener() {
@Override
@@ -76,11 +69,6 @@
if (item.getItemId() == MENU_RESET) {
mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
reset();
- } else if (item.getItemId() == MENU_REMOVE_LABELS) {
- item.setChecked(!item.isChecked());
- mTunerService.setValue(
- QSPanelController.QS_REMOVE_LABELS, item.isChecked() ? "1" : "0");
- return false;
}
return false;
}
@@ -111,20 +99,11 @@
}
};
- private final TunerService.Tunable mTunable = new TunerService.Tunable() {
- @Override
- public void onTuningChanged(String key, String newValue) {
- mToolbar.getMenu().findItem(MENU_REMOVE_LABELS)
- .setChecked(newValue != null && !("0".equals(newValue)));
- }
- };
-
@Inject
protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
QSTileHost qsTileHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
KeyguardStateController keyguardStateController, LightBarController lightBarController,
- ConfigurationController configurationController, UiEventLogger uiEventLogger,
- TunerService tunerService, @Named(QS_LABELS_FLAG) boolean qsLabelsFlag) {
+ ConfigurationController configurationController, UiEventLogger uiEventLogger) {
super(view);
mTileQueryHelper = tileQueryHelper;
mQsTileHost = qsTileHost;
@@ -136,21 +115,12 @@
mUiEventLogger = uiEventLogger;
mToolbar = mView.findViewById(com.android.internal.R.id.action_bar);
- mQsLabelsFlag = qsLabelsFlag;
-
- mTunerService = tunerService;
}
- @Override
- protected void onInit() {
- super.onInit();
- mView.getRemoveItem().setVisible(mQsLabelsFlag);
- }
@Override
protected void onViewAttached() {
mView.updateNavBackDrop(getResources().getConfiguration(), mLightBarController);
- mTunerService.addTunable(mTunable, QSPanelController.QS_REMOVE_LABELS);
mConfigurationController.addCallback(mConfigurationListener);
@@ -181,7 +151,6 @@
@Override
protected void onViewDetached() {
- mTunerService.removeTunable(mTunable);
mTileQueryHelper.setListener(null);
mToolbar.setOnMenuItemClickListener(null);
mConfigurationController.removeCallback(mConfigurationListener);
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 048fdc3..7a91421 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -75,6 +75,8 @@
private static final int ACTION_ADD = 1;
private static final int ACTION_MOVE = 2;
+ private static final int NUM_COLUMNS_ID = R.integer.quick_settings_edit_num_columns;
+
private final Context mContext;
private final Handler mHandler = new Handler();
@@ -87,6 +89,7 @@
private int mEditIndex;
private int mTileDividerIndex;
private int mFocusIndex;
+
private boolean mNeedsFocus;
private List<String> mCurrentSpecs;
private List<TileInfo> mOtherTiles;
@@ -109,7 +112,7 @@
mDecoration = new TileItemDecoration(context);
mMarginDecoration = new MarginTileDecoration();
mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
- mNumColumns = context.getResources().getInteger(R.integer.quick_settings_num_columns);
+ mNumColumns = context.getResources().getInteger(NUM_COLUMNS_ID);
mAccessibilityDelegate = new TileAdapterDelegate();
}
@@ -129,7 +132,7 @@
* @return {@code true} if the number of columns changed, {@code false} otherwise
*/
public boolean updateNumColumns() {
- int numColumns = mContext.getResources().getInteger(R.integer.quick_settings_num_columns);
+ int numColumns = mContext.getResources().getInteger(NUM_COLUMNS_ID);
if (numColumns != mNumColumns) {
mNumColumns = numColumns;
return true;
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 35a8257..10192bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -21,6 +21,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.util.settings.GlobalSettings;
import javax.inject.Named;
@@ -31,6 +32,8 @@
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
@@ -46,4 +49,11 @@
static boolean isReduceBrightColorsAvailable(Context context) {
return ColorDisplayManager.isReduceBrightColorsAvailable(context);
}
+
+ @Provides
+ @SysUISingleton
+ @Named(PM_LITE_ENABLED)
+ static boolean isPMLiteEnabled(FeatureFlags featureFlags, GlobalSettings globalSettings) {
+ return featureFlags.isPMLiteEnabled() && globalSettings.getInt(PM_LITE_SETTING, 0) != 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index a699e2e..207b25d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -105,24 +105,27 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mLabel.setSingleLine(false);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- // Remeasure view if the primary label requires more then 2 lines or the secondary label
- // text will be cut off.
- if (mLabel.getLineCount() > mMaxLabelLines || !TextUtils.isEmpty(mSecondLine.getText())
- && mSecondLine.getLineHeight() > mSecondLine.getHeight()) {
- if (!mLabel.isSingleLine()) {
- mLabel.setSingleLine();
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- } else {
- if (mLabel.isSingleLine()) {
- mLabel.setSingleLine(false);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
+ // Remeasure view if the primary label requires more than mMaxLabelLines lines or the
+ // secondary label text will be cut off.
+ if (shouldLabelBeSingleLine()) {
+ mLabel.setSingleLine();
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
+ private boolean shouldLabelBeSingleLine() {
+ if (mLabel.getLineCount() > mMaxLabelLines) {
+ return true;
+ } else if (!TextUtils.isEmpty(mSecondLine.getText())
+ && mLabel.getLineCount() > mMaxLabelLines - 1) {
+ return true;
+ }
+ return false;
+ }
+
@Override
protected void handleStateChanged(QSTile.State state) {
super.handleStateChanged(state);
@@ -171,9 +174,4 @@
mLabelContainer.setClickable(false);
mLabelContainer.setLongClickable(false);
}
-
- @Override
- public void setShowLabels(boolean show) {
- mHandler.post(() -> mLabelContainer.setVisibility(show ? VISIBLE : GONE));
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index dc81b702..07d48f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tileimpl
+import android.animation.ValueAnimator
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
@@ -24,20 +25,24 @@
import android.graphics.drawable.RippleDrawable
import android.service.quicksettings.Tile.STATE_ACTIVE
import android.view.Gravity
-import android.view.View
import android.widget.LinearLayout
+import android.widget.RelativeLayout
import com.android.systemui.R
import com.android.systemui.plugins.qs.QSIconView
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState
+// Placeholder
+private const val CORNER_RADIUS = 40f
+
class QSTileViewHorizontal(
context: Context,
icon: QSIconView
) : QSTileView(context, icon, false) {
private var paintDrawable: PaintDrawable? = null
- private var divider: View? = null
+ private var paintColor = Color.TRANSPARENT
+ private var paintAnimator: ValueAnimator? = null
init {
orientation = HORIZONTAL
@@ -49,7 +54,12 @@
override fun createLabel() {
super.createLabel()
- findViewById<LinearLayout>(R.id.label_group)?.gravity = Gravity.START
+ findViewById<LinearLayout>(R.id.label_group)?.apply {
+ gravity = Gravity.START
+ (layoutParams as? RelativeLayout.LayoutParams)?.apply {
+ removeRule(RelativeLayout.ALIGN_PARENT_TOP)
+ }
+ }
mLabel.gravity = Gravity.START
mLabel.textDirection = TEXT_DIRECTION_LOCALE
mSecondLine.gravity = Gravity.START
@@ -57,7 +67,7 @@
val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
mLabelContainer.setPaddingRelative(0, padding, padding, padding)
(mLabelContainer.layoutParams as LayoutParams).gravity =
- Gravity.CENTER_VERTICAL or Gravity.START
+ Gravity.CENTER_VERTICAL or Gravity.START
}
override fun updateRippleSize() {
@@ -66,8 +76,8 @@
override fun newTileBackground(): Drawable? {
val d = super.newTileBackground()
if (paintDrawable == null) {
- paintDrawable = PaintDrawable(Color.WHITE).apply {
- setCornerRadius(50f)
+ paintDrawable = PaintDrawable(paintColor).apply {
+ setCornerRadius(CORNER_RADIUS)
}
}
if (d is RippleDrawable) {
@@ -90,10 +100,39 @@
override fun handleStateChanged(state: QSTile.State) {
super.handleStateChanged(state)
- paintDrawable?.setTint(getCircleColor(state.state))
mSecondLine.setTextColor(mLabel.textColors)
mLabelContainer.background = null
- divider?.backgroundTintList = mLabel.textColors
+
+ val allowAnimations = animationsEnabled() && paintColor != Color.TRANSPARENT
+ val newColor = getCircleColor(state.state)
+ if (allowAnimations) {
+ animateToNewState(newColor)
+ } else {
+ if (newColor != paintColor) {
+ clearAnimator()
+ paintDrawable?.paint?.color = newColor
+ paintDrawable?.invalidateSelf()
+ }
+ }
+ paintColor = newColor
+ }
+
+ private fun animateToNewState(newColor: Int) {
+ if (newColor != paintColor) {
+ clearAnimator()
+ paintAnimator = ValueAnimator.ofArgb(paintColor, newColor)
+ .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
+ addUpdateListener { animation: ValueAnimator ->
+ paintDrawable?.paint?.color = animation.animatedValue as Int
+ paintDrawable?.invalidateSelf()
+ }
+ start()
+ }
+ }
+ }
+
+ private fun clearAnimator() {
+ paintAnimator?.cancel()?.also { paintAnimator = null }
}
override fun handleExpand(dualTarget: Boolean) {}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 3841dac..70287cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -16,10 +16,13 @@
package com.android.systemui.qs.tiles;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+import static android.content.pm.PackageManager.FEATURE_CAMERA_TOGGLE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
@@ -58,8 +61,8 @@
@Override
public boolean isAvailable() {
- return /*getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
- && */whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ return getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
+ && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
"camera_toggle_enabled",
false));
}
@@ -75,7 +78,7 @@
}
@Override
- public int getSensorId() {
+ public @Sensor int getSensorId() {
return CAMERA;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 1dddc45..f03ce2c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -54,6 +54,7 @@
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -269,13 +270,10 @@
private final NetworkController.SignalCallback mSignalCallback =
new NetworkController.SignalCallback() {
@Override
- public void setWifiIndicators(boolean enabled,
- NetworkController.IconState statusIcon,
- NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
- String description, boolean isTransient, String statusLabel) {
+ public void setWifiIndicators(WifiIndicators indicators) {
// statusIcon.visible has the connected status information
- boolean enabledAndConnected =
- enabled && (qsIcon == null ? false : qsIcon.visible);
+ boolean enabledAndConnected = indicators.enabled
+ && (indicators.qsIcon == null ? false : indicators.qsIcon.visible);
if (enabledAndConnected != mWifiConnected) {
mWifiConnected = enabledAndConnected;
// Hotspot is not connected, so changes here should update
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 720c5dc..6a574d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import javax.inject.Inject;
@@ -264,21 +265,17 @@
private final CallbackInfo mInfo = new CallbackInfo();
@Override
- public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut,
- CharSequence typeContentDescription,
- CharSequence typeContentDescriptionHtml, CharSequence description,
- boolean isWide, int subId, boolean roaming, boolean showTriangle) {
- if (qsIcon == null) {
+ public void setMobileDataIndicators(MobileDataIndicators indicators) {
+ if (indicators.qsIcon == null) {
// Not data sim, don't display.
return;
}
mInfo.dataSubscriptionName = mController.getMobileDataNetworkName();
- mInfo.dataContentDescription =
- (description != null) ? typeContentDescriptionHtml : null;
- mInfo.activityIn = activityIn;
- mInfo.activityOut = activityOut;
- mInfo.roaming = roaming;
+ mInfo.dataContentDescription = indicators.description != null
+ ? indicators.typeContentDescriptionHtml : null;
+ mInfo.activityIn = indicators.activityIn;
+ mInfo.activityOut = indicators.activityOut;
+ mInfo.roaming = indicators.roaming;
mInfo.multipleSubs = mController.getNumberSubscriptions() > 1;
refreshState(mInfo);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 946d041..e1a1fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -51,7 +51,9 @@
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import com.android.systemui.statusbar.policy.WifiIcons;
import java.io.FileDescriptor;
@@ -234,70 +236,44 @@
@Override
- public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
- boolean activityIn, boolean activityOut, String description, boolean isTransient,
- String statusLabel) {
+ public void setWifiIndicators(WifiIndicators indicators) {
if (DEBUG) {
- Log.d(TAG, "setWifiIndicators: "
- + "enabled = " + enabled + ","
- + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
- + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
- + "activityIn = " + activityIn + ","
- + "activityOut = " + activityOut + ","
- + "description = " + description + ","
- + "isTransient = " + isTransient + ","
- + "statusLabel = " + statusLabel);
+ Log.d(TAG, "setWifiIndicators: " + indicators);
}
- mWifiInfo.mEnabled = enabled;
- if (qsIcon == null) {
+ mWifiInfo.mEnabled = indicators.enabled;
+ if (indicators.qsIcon == null) {
return;
}
- mWifiInfo.mConnected = qsIcon.visible;
- mWifiInfo.mWifiSignalIconId = qsIcon.icon;
- mWifiInfo.mWifiSignalContentDescription = qsIcon.contentDescription;
- mWifiInfo.mSsid = description;
- mWifiInfo.mActivityIn = activityIn;
- mWifiInfo.mActivityOut = activityOut;
- mWifiInfo.mIsTransient = isTransient;
- mWifiInfo.mStatusLabel = statusLabel;
+ mWifiInfo.mConnected = indicators.qsIcon.visible;
+ mWifiInfo.mWifiSignalIconId = indicators.qsIcon.icon;
+ mWifiInfo.mWifiSignalContentDescription = indicators.qsIcon.contentDescription;
+ mWifiInfo.mEnabled = indicators.enabled;
+ mWifiInfo.mSsid = indicators.description;
+ mWifiInfo.mActivityIn = indicators.activityIn;
+ mWifiInfo.mActivityOut = indicators.activityOut;
+ mWifiInfo.mIsTransient = indicators.isTransient;
+ mWifiInfo.mStatusLabel = indicators.statusLabel;
refreshState(mWifiInfo);
}
@Override
- public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut,
- CharSequence typeContentDescription,
- CharSequence typeContentDescriptionHtml, CharSequence description,
- boolean isWide, int subId, boolean roaming, boolean showTriangle) {
+ public void setMobileDataIndicators(MobileDataIndicators indicators) {
if (DEBUG) {
- Log.d(TAG, "setMobileDataIndicators: "
- + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
- + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
- + "statusType = " + statusType + ","
- + "qsType = " + qsType + ","
- + "activityIn = " + activityIn + ","
- + "activityOut = " + activityOut + ","
- + "typeContentDescription = " + typeContentDescription + ","
- + "typeContentDescriptionHtml = " + typeContentDescriptionHtml + ","
- + "description = " + description + ","
- + "isWide = " + isWide + ","
- + "subId = " + subId + ","
- + "roaming = " + roaming + ","
- + "showTriangle = " + showTriangle);
+ Log.d(TAG, "setMobileDataIndicators: " + indicators);
}
- if (qsIcon == null) {
+ if (indicators.qsIcon == null) {
// Not data sim, don't display.
return;
}
- mCellularInfo.mDataSubscriptionName =
- description == null ? mController.getMobileDataNetworkName() : description;
- mCellularInfo.mDataContentDescription =
- (description != null) ? typeContentDescriptionHtml : null;
- mCellularInfo.mMobileSignalIconId = qsIcon.icon;
- mCellularInfo.mQsTypeIcon = qsType;
- mCellularInfo.mActivityIn = activityIn;
- mCellularInfo.mActivityOut = activityOut;
- mCellularInfo.mRoaming = roaming;
+ mCellularInfo.mDataSubscriptionName = indicators.description == null
+ ? mController.getMobileDataNetworkName() : indicators.description;
+ mCellularInfo.mDataContentDescription = indicators.description != null
+ ? indicators.typeContentDescriptionHtml : null;
+ mCellularInfo.mMobileSignalIconId = indicators.qsIcon.icon;
+ mCellularInfo.mQsTypeIcon = indicators.qsType;
+ mCellularInfo.mActivityIn = indicators.activityIn;
+ mCellularInfo.mActivityOut = indicators.activityOut;
+ mCellularInfo.mRoaming = indicators.roaming;
mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1;
refreshState(mCellularInfo);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index 2f0071a..e9b712d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -16,10 +16,13 @@
package com.android.systemui.qs.tiles;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+import static android.content.pm.PackageManager.FEATURE_MICROPHONE_TOGGLE;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
@@ -58,7 +61,9 @@
@Override
public boolean isAvailable() {
- return whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ return getHost().getContext().getPackageManager()
+ .hasSystemFeature(FEATURE_MICROPHONE_TOGGLE)
+ && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
"mic_toggle_enabled",
false));
}
@@ -74,7 +79,7 @@
}
@Override
- public int getSensorId() {
+ public @Sensor int getSensorId() {
return MICROPHONE;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 00703e7..0c582bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -17,7 +17,7 @@
package com.android.systemui.qs.tiles;
import android.content.Intent;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
import android.service.quicksettings.Tile;
@@ -49,7 +49,7 @@
/**
* @return Id of the sensor that will be toggled
*/
- public abstract @IndividualSensor int getSensorId();
+ public abstract @Sensor int getSensorId();
/**
* @return icon for the QS tile
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index a6fd011..341e67c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -51,8 +51,8 @@
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import com.android.systemui.statusbar.policy.WifiIcons;
import com.android.wifitrackerlib.WifiEntry;
@@ -303,22 +303,20 @@
final CallbackInfo mInfo = new CallbackInfo();
@Override
- public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
- boolean activityIn, boolean activityOut, String description, boolean isTransient,
- String statusLabel) {
- if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
- if (qsIcon == null) {
+ public void setWifiIndicators(WifiIndicators indicators) {
+ if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + indicators.enabled);
+ if (indicators.qsIcon == null) {
return;
}
- mInfo.enabled = enabled;
- mInfo.connected = qsIcon.visible;
- mInfo.wifiSignalIconId = qsIcon.icon;
- mInfo.ssid = description;
- mInfo.activityIn = activityIn;
- mInfo.activityOut = activityOut;
- mInfo.wifiSignalContentDescription = qsIcon.contentDescription;
- mInfo.isTransient = isTransient;
- mInfo.statusLabel = statusLabel;
+ mInfo.enabled = indicators.enabled;
+ mInfo.connected = indicators.qsIcon.visible;
+ mInfo.wifiSignalIconId = indicators.qsIcon.icon;
+ mInfo.ssid = indicators.description;
+ mInfo.activityIn = indicators.activityIn;
+ mInfo.activityOut = indicators.activityOut;
+ mInfo.wifiSignalContentDescription = indicators.qsIcon.contentDescription;
+ mInfo.isTransient = indicators.isTransient;
+ mInfo.statusLabel = indicators.statusLabel;
if (isShowingDetail()) {
mDetailAdapter.updateItems();
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
index 53d9f1c..5b55864 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
@@ -140,6 +140,25 @@
}
/**
+ * Set the given boundary to the given value without animation.
+ */
+ public void setBoundaryTo(CropBoundary boundary, float value) {
+ switch (boundary) {
+ case TOP:
+ mTopCrop = value;
+ break;
+ case BOTTOM:
+ mBottomCrop = value;
+ break;
+ case NONE:
+ Log.w(TAG, "No boundary selected for animation");
+ break;
+ }
+
+ invalidate();
+ }
+
+ /**
* Animate the given boundary to the given value.
*/
public void animateBoundaryTo(CropBoundary boundary, float value) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 89efda9..5a13ea55 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -20,8 +20,17 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.HardwareRenderer;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -33,6 +42,14 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.time.ZonedDateTime;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -44,9 +61,21 @@
public class LongScreenshotActivity extends Activity {
private static final String TAG = "LongScreenshotActivity";
+ private static final String IMAGE_PATH_KEY = "saved-image";
+ private static final String TOP_BOUNDARY_KEY = "top-boundary";
+ private static final String BOTTOM_BOUNDARY_KEY = "bottom-boundary";
+
private final UiEventLogger mUiEventLogger;
private final ScrollCaptureController mScrollCaptureController;
private final ScrollCaptureClient.Connection mConnection;
+ private final Executor mUiExecutor;
+ private final Executor mBackgroundExecutor;
+ private final ImageExporter mImageExporter;
+
+ private String mSavedImagePath;
+ // If true, the activity is re-loading an image from storage, which should either succeed and
+ // populate the UI or fail and finish the activity.
+ private boolean mRestoringInstance;
private ImageView mPreview;
private View mSave;
@@ -69,6 +98,9 @@
@Background Executor bgExecutor,
Context context) {
mUiEventLogger = uiEventLogger;
+ mUiExecutor = mainExecutor;
+ mBackgroundExecutor = bgExecutor;
+ mImageExporter = imageExporter;
mScrollCaptureController = new ScrollCaptureController(context, mainExecutor, bgExecutor,
imageExporter);
@@ -95,12 +127,42 @@
mCancel.setOnClickListener(this::onClicked);
mEdit.setOnClickListener(this::onClicked);
mShare.setOnClickListener(this::onClicked);
+
+ if (savedInstanceState != null) {
+ String imagePath = savedInstanceState.getString(IMAGE_PATH_KEY);
+ if (!TextUtils.isEmpty(imagePath)) {
+ mRestoringInstance = true;
+ mBackgroundExecutor.execute(() -> {
+ Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
+ if (bitmap == null) {
+ Log.e(TAG, "Failed to read bitmap from " + imagePath);
+ finishAndRemoveTask();
+ } else {
+ runOnUiThread(() -> {
+ BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap);
+ mPreview.setImageDrawable(drawable);
+ mMagnifierView.setDrawable(drawable, bitmap.getWidth(),
+ bitmap.getHeight());
+
+ mCropView.setBoundaryTo(CropView.CropBoundary.TOP,
+ savedInstanceState.getFloat(TOP_BOUNDARY_KEY, 0f));
+ mCropView.setBoundaryTo(CropView.CropBoundary.BOTTOM,
+ savedInstanceState.getFloat(BOTTOM_BOUNDARY_KEY, 1f));
+ mRestoringInstance = false;
+ // Reuse the same path for subsequent restoration.
+ mSavedImagePath = imagePath;
+ Log.d(TAG, "Loaded bitmap from " + imagePath);
+ });
+ }
+ });
+ }
+ }
}
@Override
public void onStart() {
super.onStart();
- if (mPreview.getDrawable() == null) {
+ if (mPreview.getDrawable() == null && !mRestoringInstance) {
if (mConnection == null) {
Log.e(TAG, "Failed to get scroll capture connection, bailing out");
finishAndRemoveTask();
@@ -110,6 +172,24 @@
}
}
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(IMAGE_PATH_KEY, mSavedImagePath);
+ outState.putFloat(TOP_BOUNDARY_KEY, mCropView.getTopBoundary());
+ outState.putFloat(BOTTOM_BOUNDARY_KEY, mCropView.getBottomBoundary());
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (isFinishing() && !TextUtils.isEmpty(mSavedImagePath)) {
+ Log.d(TAG, "Deleting " + mSavedImagePath);
+ File file = new File(mSavedImagePath);
+ file.delete();
+ }
+ }
+
private void setButtonsEnabled(boolean enabled) {
mSave.setEnabled(enabled);
mCancel.setEnabled(enabled);
@@ -161,50 +241,89 @@
}
private void startExport(PendingAction action) {
- mScrollCaptureController.startExport(mCropView.getTopBoundary(),
- mCropView.getBottomBoundary(), new ScrollCaptureController.ExportCallback() {
- @Override
- public void onError() {
- Log.e(TAG, "Error exporting image data.");
- setButtonsEnabled(true);
- }
+ Drawable drawable = mPreview.getDrawable();
- @Override
- public void onExportComplete(Uri outputUri) {
- setButtonsEnabled(true);
- switch (action) {
- case EDIT:
- doEdit(outputUri);
- break;
- case SHARE:
- doShare(outputUri);
- break;
- case SAVE:
- // Nothing more to do
- finishAndRemoveTask();
- break;
- }
- }
- });
+ Rect croppedPortion = new Rect(
+ 0,
+ (int) (drawable.getIntrinsicHeight() * mCropView.getTopBoundary()),
+ drawable.getIntrinsicWidth(),
+ (int) (drawable.getIntrinsicHeight() * mCropView.getBottomBoundary()));
+ ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
+ mBackgroundExecutor, UUID.randomUUID(), getBitmap(croppedPortion, drawable),
+ ZonedDateTime.now());
+ exportFuture.addListener(() -> {
+ try {
+ ImageExporter.Result result = exportFuture.get();
+ setButtonsEnabled(true);
+ switch (action) {
+ case EDIT:
+ doEdit(result.uri);
+ break;
+ case SHARE:
+ doShare(result.uri);
+ break;
+ case SAVE:
+ // Nothing more to do
+ finishAndRemoveTask();
+ break;
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ Log.e(TAG, "failed to export", e);
+ setButtonsEnabled(true);
+ }
+ }, mUiExecutor);
+ }
+
+ private Bitmap getBitmap(Rect bounds, Drawable drawable) {
+ final RenderNode output = new RenderNode("Bitmap Export");
+ output.setPosition(0, 0, bounds.width(), bounds.height());
+ RecordingCanvas canvas = output.beginRecording();
+ // Translating the canvas instead of setting drawable bounds since the drawable is still
+ // used in the preview.
+ canvas.translate(0, -bounds.top);
+ drawable.draw(canvas);
+ output.endRecording();
+ return HardwareRenderer.createHardwareBitmap(output, bounds.width(), bounds.height());
+ }
+
+ private void saveCacheBitmap(ImageTileSet tileSet) {
+ long startTime = SystemClock.uptimeMillis();
+ Bitmap bitmap = tileSet.toBitmap();
+ // TODO(b/181562529) Remove this
+ mPreview.setImageDrawable(tileSet.getDrawable());
+ try {
+ File file = File.createTempFile("long_screenshot", ".png", null);
+ FileOutputStream stream = new FileOutputStream(file);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+ stream.flush();
+ stream.close();
+ mSavedImagePath = file.getAbsolutePath();
+ Log.d(TAG, "Saved to " + file.getAbsolutePath() + " in "
+ + (SystemClock.uptimeMillis() - startTime) + "ms");
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to save bitmap", e);
+ }
}
private void doCapture() {
mScrollCaptureController.start(mConnection,
new ScrollCaptureController.ScrollCaptureCallback() {
- @Override
- public void onError() {
- Log.e(TAG, "Error!");
- finishAndRemoveTask();
- }
+ @Override
+ public void onError() {
+ Log.e(TAG, "Error capturing long screenshot!");
+ finishAndRemoveTask();
+ }
- @Override
- public void onComplete(ImageTileSet imageTileSet) {
- Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
- + imageTileSet.getHeight());
- mPreview.setImageDrawable(imageTileSet.getDrawable());
- mMagnifierView.setImageTileset(imageTileSet);
- mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
- }
- });
+ @Override
+ public void onComplete(ImageTileSet imageTileSet) {
+ Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
+ + imageTileSet.getHeight());
+ mPreview.setImageDrawable(imageTileSet.getDrawable());
+ mMagnifierView.setDrawable(imageTileSet.getDrawable(),
+ imageTileSet.getWidth(), imageTileSet.getHeight());
+ mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
+ mBackgroundExecutor.execute(() -> saveCacheBitmap(imageTileSet));
+ }
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
index f8f1d3a..7a0ec4c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
@@ -16,6 +16,7 @@
package com.android.systemui.screenshot;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -77,13 +78,12 @@
mCheckerboardPaint.setColor(Color.GRAY);
}
- public void setImageTileset(ImageTileSet tiles) {
- if (tiles != null) {
- mDrawable = tiles.getDrawable();
- mDrawable.setBounds(0, 0, tiles.getWidth(), tiles.getHeight());
- } else {
- mDrawable = null;
- }
+ /**
+ * Set the drawable to be displayed by the magnifier.
+ */
+ public void setDrawable(@NonNull Drawable drawable, int width, int height) {
+ mDrawable = drawable;
+ mDrawable.setBounds(0, 0, width, height);
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 131fde6..805ac7c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -325,6 +325,7 @@
attachWindow();
mWindow.setContentView(mScreenshotView);
+ mScreenshotView.requestApplyInsets();
mScreenshotView.takePartialScreenshot(
rect -> takeScreenshotInternal(finisher, rect));
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index dc639dc..54b99bb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -21,24 +21,25 @@
import static java.lang.Math.min;
import static java.util.Objects.requireNonNull;
+import android.annotation.BinderThread;
import android.annotation.UiContext;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.media.Image;
import android.media.ImageReader;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.util.Log;
import android.view.IScrollCaptureCallbacks;
import android.view.IScrollCaptureConnection;
import android.view.IWindowManager;
+import android.view.ScrollCaptureResponse;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.view.ScrollCaptureViewSupport;
import java.util.function.Consumer;
@@ -62,16 +63,19 @@
*/
public interface Connection {
/**
- * Session start should be deferred until UI is active because of resource allocation and
- * potential visible side effects in the target window.
- *
+ * Start a session.
+
* @param sessionConsumer listener to receive the session once active
* @param maxPages the capture buffer size expressed as a multiple of the content height
*/
+ // TODO ListenableFuture
void start(Consumer<Session> sessionConsumer, float maxPages);
/**
- * Close the connection.
+ * Close the connection. Must end capture if started to avoid potential unwanted visual
+ * artifacts.
+ *
+ * @see Session#end(Runnable)
*/
void close();
}
@@ -119,6 +123,7 @@
* @param top the top (y) position of the tile to capture, in content rect space
* @param consumer listener to be informed of the result
*/
+ // TODO ListenableFuture
void requestTile(int top, Consumer<CaptureResult> consumer);
/**
@@ -129,16 +134,31 @@
*/
int getMaxTiles();
+ /**
+ * @return the height of each image tile
+ */
int getTileHeight();
+ /**
+ * @return the height of scrollable content being captured
+ */
int getPageHeight();
+ /**
+ * @return the width of the scrollable page
+ */
int getPageWidth();
/**
+ * @return the bounds on screen of the window being captured.
+ */
+ Rect getWindowBounds();
+
+ /**
* End the capture session, return the target app to original state. The listener
* will be called when the target app is ready to before visible and interactive.
*/
+ // TODO ListenableFuture
void end(Runnable listener);
}
@@ -185,13 +205,13 @@
+ ", taskId=" + taskId + ", consumer=" + consumer + ")");
}
mWindowManagerService.requestScrollCapture(displayId, mHostWindowToken, taskId,
- new ControllerCallbacks(consumer));
+ new ClientCallbacks(consumer));
} catch (RemoteException e) {
Log.e(TAG, "Ignored remote exception", e);
}
}
- private static class ControllerCallbacks extends IScrollCaptureCallbacks.Stub implements
+ private static class ClientCallbacks extends IScrollCaptureCallbacks.Stub implements
Connection, Session, IBinder.DeathRecipient {
private IScrollCaptureConnection mConnection;
@@ -206,46 +226,63 @@
private int mTileWidth;
private Rect mRequestRect;
private boolean mStarted;
+
+ private ICancellationSignal mCancellationSignal;
+ private Rect mWindowBounds;
+ private Rect mBoundsInWindow;
private int mMaxTiles;
- private ControllerCallbacks(Consumer<Connection> connectionConsumer) {
+ private ClientCallbacks(Consumer<Connection> connectionConsumer) {
mConnectionConsumer = connectionConsumer;
}
- // IScrollCaptureCallbacks
-
+ @BinderThread
@Override
- public void onConnected(IScrollCaptureConnection connection, Rect scrollBounds,
- Point positionInWindow) throws RemoteException {
+ public void onScrollCaptureResponse(ScrollCaptureResponse response) throws RemoteException {
if (DEBUG_SCROLL) {
- Log.d(TAG, "onConnected(connection=" + connection + ", scrollBounds=" + scrollBounds
- + ", positionInWindow=" + positionInWindow + ")");
+ Log.d(TAG, "onScrollCaptureResponse(response=" + response + ")");
}
- mConnection = connection;
- mConnection.asBinder().linkToDeath(this, 0);
- mScrollBounds = scrollBounds;
- mConnectionConsumer.accept(this);
+ if (response.isConnected()) {
+ mConnection = response.getConnection();
+ mConnection.asBinder().linkToDeath(this, 0);
+ mWindowBounds = response.getWindowBounds();
+ mBoundsInWindow = response.getBoundsInWindow();
+
+ int pxPerPage = mBoundsInWindow.width() * mBoundsInWindow.height();
+ int pxPerTile = min(TILE_SIZE_PX_MAX, (pxPerPage / TILES_PER_PAGE));
+ mTileWidth = mBoundsInWindow.width();
+ mTileHeight = pxPerTile / mBoundsInWindow.width();
+ if (DEBUG_SCROLL) {
+ Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
+ Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight);
+ Log.d(TAG, "maxHeight: " + (mMaxTiles * mTileHeight) + "px");
+ }
+ mConnectionConsumer.accept(this);
+ }
mConnectionConsumer = null;
-
- int pxPerPage = mScrollBounds.width() * mScrollBounds.height();
- int pxPerTile = min(TILE_SIZE_PX_MAX, (pxPerPage / TILES_PER_PAGE));
- mTileWidth = mScrollBounds.width();
- mTileHeight = pxPerTile / mScrollBounds.width();
- if (DEBUG_SCROLL) {
- Log.d(TAG, "scrollBounds: " + mScrollBounds);
- Log.d(TAG, "tile dimen: " + mTileWidth + "x" + mTileHeight);
- }
}
@Override
- public void onUnavailable() throws RemoteException {
+ public void start(Consumer<Session> sessionConsumer, float maxPages) {
if (DEBUG_SCROLL) {
- Log.d(TAG, "onUnavailable");
+ Log.d(TAG, "start(sessionConsumer=" + sessionConsumer + ","
+ + " maxPages=" + maxPages + ")");
}
- // The targeted app does not support scroll capture
- // or the window could not be found... etc etc.
+ mMaxTiles = (int) Math.ceil(maxPages * TILES_PER_PAGE);
+ mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
+ mMaxTiles, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ mSessionConsumer = sessionConsumer;
+
+ try {
+ mCancellationSignal = mConnection.startCapture(mReader.getSurface());
+ mStarted = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to start", e);
+ mReader.close();
+ }
}
+ @BinderThread
@Override
public void onCaptureStarted() {
if (DEBUG_SCROLL) {
@@ -256,13 +293,25 @@
}
@Override
- public void onCaptureBufferSent(long frameNumber, Rect contentArea) {
- Image image = null;
- if (frameNumber != ScrollCaptureViewSupport.NO_FRAME_PRODUCED) {
- image = mReader.acquireNextImage();
- }
+ public void requestTile(int top, Consumer<CaptureResult> consumer) {
if (DEBUG_SCROLL) {
- Log.d(TAG, "onCaptureBufferSent(frameNumber=" + frameNumber
+ Log.d(TAG, "requestTile(top=" + top + ", consumer=" + consumer + ")");
+ }
+ cancelPendingRequest();
+ mRequestRect = new Rect(0, top, mTileWidth, top + mTileHeight);
+ mResultConsumer = consumer;
+ try {
+ mCancellationSignal = mConnection.requestImage(mRequestRect);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught remote exception from requestImage", e);
+ }
+ }
+
+ @Override
+ public void onImageRequestCompleted(int flags, Rect contentArea) {
+ Image image = mReader.acquireLatestImage();
+ if (DEBUG_SCROLL) {
+ Log.d(TAG, "onCaptureBufferSent(flags=" + flags
+ ", contentArea=" + contentArea + ") image=" + image);
}
// Save and clear first, since the consumer will likely request the next
@@ -273,61 +322,13 @@
}
@Override
- public void onConnectionClosed() {
- if (DEBUG_SCROLL) {
- Log.d(TAG, "onConnectionClosed()");
- }
- disconnect();
- if (mShutdownListener != null) {
- mShutdownListener.run();
- mShutdownListener = null;
- }
- }
-
- // Misc
-
- private void disconnect() {
- if (mConnection != null) {
- mConnection.asBinder().unlinkToDeath(this, 0);
- }
- mConnection = null;
- }
-
- // ScrollCaptureController.Connection
-
- @Override
- public void start(Consumer<Session> sessionConsumer, float maxPages) {
- if (DEBUG_SCROLL) {
- Log.d(TAG, "start(sessionConsumer=" + sessionConsumer + ","
- + " maxPages=" + maxPages + ")"
- + " [maxHeight: " + (mMaxTiles * mTileHeight) + "px]");
- }
- mMaxTiles = (int) Math.ceil(maxPages * TILES_PER_PAGE);
- mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
- mMaxTiles, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
- mSessionConsumer = sessionConsumer;
- try {
- mConnection.startCapture(mReader.getSurface());
- mStarted = true;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to start", e);
- }
- }
-
- @Override
- public void close() {
- end(null);
- }
-
- // ScrollCaptureController.Session
-
- @Override
public void end(Runnable listener) {
if (DEBUG_SCROLL) {
Log.d(TAG, "end(listener=" + listener + ")");
}
if (mStarted) {
mShutdownListener = listener;
+ mReader.close();
try {
// listener called from onConnectionClosed callback
mConnection.endCapture();
@@ -342,40 +343,37 @@
}
}
+ @BinderThread
@Override
- public int getPageHeight() {
- return mScrollBounds.height();
- }
-
- @Override
- public int getPageWidth() {
- return mScrollBounds.width();
- }
-
- @Override
- public int getTileHeight() {
- return mTileHeight;
- }
-
- @Override
- public int getMaxTiles() {
- return mMaxTiles;
- }
-
- @Override
- public void requestTile(int top, Consumer<CaptureResult> consumer) {
- if (DEBUG_SCROLL) {
- Log.d(TAG, "requestTile(top=" + top + ", consumer=" + consumer + ")");
+ public void onCaptureEnded() {
+ close();
+ if (mShutdownListener != null) {
+ mShutdownListener.run();
+ mShutdownListener = null;
}
- mRequestRect = new Rect(0, top, mTileWidth, top + mTileHeight);
- mResultConsumer = consumer;
- try {
- mConnection.requestImage(mRequestRect);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught remote exception from requestImage", e);
+ }
+
+ @Override
+ public void close() {
+ if (mConnection != null) {
+ try {
+ mConnection.close();
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ disconnect();
}
}
+ // Misc
+
+ private void disconnect() {
+ if (mConnection != null) {
+ mConnection.asBinder().unlinkToDeath(this, 0);
+ }
+ mConnection = null;
+ }
+
/**
* The process hosting the window went away abruptly!
*/
@@ -386,5 +384,40 @@
}
disconnect();
}
+
+ @Override
+ public int getPageHeight() {
+ return mBoundsInWindow.height();
+ }
+
+ @Override
+ public int getPageWidth() {
+ return mBoundsInWindow.width();
+ }
+
+ @Override
+ public int getTileHeight() {
+ return mTileHeight;
+ }
+
+ public Rect getWindowBounds() {
+ return new Rect(mWindowBounds);
+ }
+
+ @Override
+ public int getMaxTiles() {
+ return mMaxTiles;
+ }
+
+ private void cancelPendingRequest() {
+ if (mCancellationSignal != null) {
+ try {
+ mCancellationSignal.cancel();
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ mCancellationSignal = null;
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 4a3ffa45..bf65132 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -18,7 +18,6 @@
import android.annotation.UiThread;
import android.content.Context;
-import android.graphics.Rect;
import android.net.Uri;
import android.provider.Settings;
import android.util.Log;
@@ -27,11 +26,8 @@
import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
import com.android.systemui.screenshot.ScrollCaptureClient.Session;
-import com.google.common.util.concurrent.ListenableFuture;
-
import java.time.ZonedDateTime;
import java.util.UUID;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
/**
@@ -89,29 +85,6 @@
connection.start(this::startCapture, maxPages);
}
- /**
- * @param topCrop [0,1) fraction of the top of the image to be cropped out.
- * @param bottomCrop (0, 1] fraction to be cropped out, e.g. 0.7 will crop out the bottom 30%.
- */
- public void startExport(float topCrop, float bottomCrop, ExportCallback callback) {
- Rect croppedPortion = new Rect(
- 0,
- (int) (mImageTileSet.getHeight() * topCrop),
- mImageTileSet.getWidth(),
- (int) (mImageTileSet.getHeight() * bottomCrop));
- ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
- mBgExecutor, mRequestId, mImageTileSet.toBitmap(croppedPortion), mCaptureTime);
- exportFuture.addListener(() -> {
- try {
- ImageExporter.Result result = exportFuture.get();
- callback.onExportComplete(result.uri);
- } catch (InterruptedException | ExecutionException e) {
- Log.e(TAG, "failed to export", e);
- callback.onError();
- }
- }, mUiExecutor);
- }
-
private void onCaptureResult(CaptureResult result) {
Log.d(TAG, "onCaptureResult: " + result);
boolean emptyResult = result.captured.height() == 0;
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
index 9f182e1..6586137 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -25,8 +25,8 @@
import android.content.res.Resources
import android.hardware.SensorPrivacyManager
import android.hardware.SensorPrivacyManager.EXTRA_SENSOR
-import android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA
-import android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
import android.os.Bundle
import android.os.Handler
import android.text.Html
@@ -81,7 +81,7 @@
dismiss()
}
}
- if (!sensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor)) {
+ if (!sensorPrivacyManager.isSensorPrivacyEnabled(sensor)) {
finish()
return
}
@@ -89,9 +89,9 @@
mAlertParams.apply {
try {
mMessage = Html.fromHtml(getString(when (sensor) {
- INDIVIDUAL_SENSOR_MICROPHONE ->
+ MICROPHONE ->
R.string.sensor_privacy_start_use_mic_dialog_content
- INDIVIDUAL_SENSOR_CAMERA ->
+ CAMERA ->
R.string.sensor_privacy_start_use_camera_dialog_content
else -> Resources.ID_NULL
}, packageManager.getApplicationInfo(sensorUsePackageName, 0)
@@ -102,9 +102,9 @@
}
mIconId = when (sensor) {
- INDIVIDUAL_SENSOR_MICROPHONE ->
+ MICROPHONE ->
com.android.internal.R.drawable.perm_group_microphone
- INDIVIDUAL_SENSOR_CAMERA -> com.android.internal.R.drawable.perm_group_camera
+ CAMERA -> com.android.internal.R.drawable.perm_group_camera
else -> Resources.ID_NULL
}
@@ -121,7 +121,7 @@
override fun onStart() {
super.onStart()
- sensorPrivacyManager.suppressIndividualSensorPrivacyReminders(sensorUsePackageName, true)
+ sensorPrivacyManager.suppressSensorPrivacyReminders(sensorUsePackageName, true)
unsuppressImmediately = false
}
@@ -156,11 +156,11 @@
if (unsuppressImmediately) {
sensorPrivacyManager
- .suppressIndividualSensorPrivacyReminders(sensorUsePackageName, false)
+ .suppressSensorPrivacyReminders(sensorUsePackageName, false)
} else {
Handler(mainLooper).postDelayed({
sensorPrivacyManager
- .suppressIndividualSensorPrivacyReminders(sensorUsePackageName, false)
+ .suppressSensorPrivacyReminders(sensorUsePackageName, false)
}, SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS)
}
}
@@ -170,7 +170,7 @@
}
private fun disableSensorPrivacy() {
- sensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, false)
+ sensorPrivacyManager.setSensorPrivacyForProfileGroup(sensor, false)
unsuppressImmediately = true
setResult(RESULT_OK)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index cf77e29..1d59257 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -86,4 +86,8 @@
public boolean isNavigationBarOverlayEnabled() {
return mFlagReader.isEnabled(R.bool.flag_navigation_bar_overlay);
}
+
+ public boolean isPMLiteEnabled() {
+ return mFlagReader.isEnabled(R.bool.flag_pm_lite);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 7e2d27a..a4e97a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -41,6 +42,7 @@
import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.graphics.Color;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.face.FaceManager;
@@ -277,10 +279,7 @@
// avoid calling this method since it has an IPC
if (whitelistIpcs(this::isOrganizationOwnedDevice)) {
final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
- final CharSequence disclosure = organizationName != null
- ? mContext.getResources().getString(R.string.do_disclosure_with_name,
- organizationName)
- : mContext.getResources().getText(R.string.do_disclosure_generic);
+ final CharSequence disclosure = getDisclosureText(organizationName);
mRotateTextViewController.updateIndication(
INDICATION_TYPE_DISCLOSURE,
new KeyguardIndication.Builder()
@@ -297,6 +296,22 @@
}
}
+ private CharSequence getDisclosureText(@Nullable CharSequence organizationName) {
+ final Resources packageResources = mContext.getResources();
+ if (organizationName == null) {
+ return packageResources.getText(R.string.do_disclosure_generic);
+ } else if (mDevicePolicyManager.isDeviceManaged()
+ && mDevicePolicyManager.getDeviceOwnerType(
+ mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+ == DEVICE_OWNER_TYPE_FINANCED) {
+ return packageResources.getString(R.string.do_financed_disclosure_with_name,
+ organizationName);
+ } else {
+ return packageResources.getString(R.string.do_disclosure_with_name,
+ organizationName);
+ }
+ }
+
private void updateOwnerInfo() {
if (!isKeyguardLayoutEnabled()) {
mRotateTextViewController.hideIndication(INDICATION_TYPE_OWNER_INFO);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index f427ba9..7691761 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -17,15 +17,11 @@
package com.android.systemui.statusbar.notification.row;
-import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
-import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -1317,7 +1313,7 @@
private boolean isBubblesEnabled() {
return Settings.Global.getInt(mContext.getContentResolver(),
- NOTIFICATION_BUBBLES, 0) == 1;
+ Settings.Global.NOTIFICATION_BUBBLES, 0) == 1;
}
/**
@@ -1373,27 +1369,26 @@
}
ImageView snoozeButton = layout.findViewById(com.android.internal.R.id.snooze_button);
View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
- LinearLayout actionContainerLayout =
- layout.findViewById(com.android.internal.R.id.actions_container_layout);
- if (snoozeButton == null || actionContainer == null || actionContainerLayout == null) {
+ if (snoozeButton == null || actionContainer == null) {
return;
}
final boolean showSnooze = Settings.Secure.getInt(mContext.getContentResolver(),
- SHOW_NOTIFICATION_SNOOZE, 0) == 1;
- if (!showSnooze) {
+ Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1;
+ // Notification.Builder can 'disable' the snooze button to prevent it from being shown here
+ boolean snoozeDisabled = !snoozeButton.isEnabled();
+ if (!showSnooze || snoozeDisabled) {
snoozeButton.setVisibility(GONE);
return;
}
- Resources res = mContext.getResources();
- Drawable snoozeDrawable = res.getDrawable(R.drawable.ic_snooze);
+ Drawable snoozeDrawable = mContext.getDrawable(R.drawable.ic_snooze);
mContainingNotification.updateNotificationColor();
snoozeDrawable.setTint(mContainingNotification.getNotificationColor());
snoozeButton.setImageDrawable(snoozeDrawable);
final NotificationSnooze snoozeGuts = (NotificationSnooze) LayoutInflater.from(mContext)
.inflate(R.layout.notification_snooze, null, false);
- final String snoozeDescription = res.getString(
+ final String snoozeDescription = mContext.getString(
R.string.notification_menu_snooze_description);
final NotificationMenuRowPlugin.MenuItem snoozeMenuItem =
new NotificationMenuRow.NotificationMenuItem(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
index 414d620..222735a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
@@ -49,7 +49,7 @@
// Custom views will most likely use just white or black as their text color.
// We need to scan through and replace these colors by Material NEXT colors.
- ensureThemeOnChildren();
+ ensureThemeOnChildren(mView);
// Let's invert the notification colors when we're in night mode and
// the notification background isn't colorized.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
index 301c372..d21ae13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
@@ -64,7 +64,7 @@
// Custom views will most likely use just white or black as their text color.
// We need to scan through and replace these colors by Material NEXT colors.
- ensureThemeOnChildren();
+ ensureThemeOnChildren(mWrappedView);
if (needsInversion(resolveBackgroundColor(), mWrappedView)) {
invertViewLuminosity(mWrappedView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 0ef4c4d..89babf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -58,9 +58,10 @@
private final Rect mTmpRect = new Rect();
protected int mBackgroundColor = 0;
- private int mLightTextColor;
- private int mDarkTextColor;
- private int mDefaultTextColor;
+ private int mMaterialTextColorPrimary;
+ private int mMaterialTextColorSecondary;
+ private int mThemedTextColorPrimary;
+ private int mThemedTextColorSecondary;
private boolean mAdjustTheme;
public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
@@ -124,15 +125,22 @@
mBackgroundColor = backgroundColor;
mView.setBackground(new ColorDrawable(Color.TRANSPARENT));
}
- mLightTextColor = mView.getContext().getColor(
- com.android.internal.R.color.notification_primary_text_color_light);
- mDarkTextColor = mView.getContext().getColor(
- com.android.internal.R.color.notification_primary_text_color_dark);
+
+ Context materialTitleContext = new ContextThemeWrapper(mView.getContext(),
+ com.android.internal.R.style.TextAppearance_Material_Notification_Title);
+ mMaterialTextColorPrimary = Utils.getColorAttr(materialTitleContext,
+ com.android.internal.R.attr.textColor).getDefaultColor();
+ Context materialContext = new ContextThemeWrapper(mView.getContext(),
+ com.android.internal.R.style.TextAppearance_Material_Notification);
+ mMaterialTextColorSecondary = Utils.getColorAttr(materialContext,
+ com.android.internal.R.attr.textColor).getDefaultColor();
Context themedContext = new ContextThemeWrapper(mView.getContext(),
com.android.internal.R.style.Theme_DeviceDefault_DayNight);
- mDefaultTextColor = Utils.getColorAttr(themedContext,
+ mThemedTextColorPrimary = Utils.getColorAttr(themedContext,
com.android.internal.R.attr.textColorPrimary).getDefaultColor();
+ mThemedTextColorSecondary = Utils.getColorAttr(themedContext,
+ com.android.internal.R.attr.textColorSecondary).getDefaultColor();
}
protected boolean needsInversion(int defaultBackgroundColor, View view) {
@@ -210,27 +218,30 @@
return false;
}
- protected void ensureThemeOnChildren() {
- if (!mAdjustTheme || mView == null) {
+ protected void ensureThemeOnChildren(View rootView) {
+ if (!mAdjustTheme || mView == null || rootView == null) {
return;
}
// Notifications with custom backgrounds should not be adjusted
if (mBackgroundColor != Color.TRANSPARENT
- || getBackgroundColor(mView) != Color.TRANSPARENT) {
+ || getBackgroundColor(mView) != Color.TRANSPARENT
+ || getBackgroundColor(rootView) != Color.TRANSPARENT) {
return;
}
// Now let's check if there's unprotected text somewhere, and apply the theme if we find it.
- processTextColorRecursive(mView);
+ processTextColorRecursive(rootView);
}
private void processTextColorRecursive(View view) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
int foreground = textView.getCurrentTextColor();
- if (foreground == mLightTextColor || foreground == mDarkTextColor) {
- textView.setTextColor(mDefaultTextColor);
+ if (foreground == mMaterialTextColorPrimary) {
+ textView.setTextColor(mThemedTextColorPrimary);
+ } else if (foreground == mMaterialTextColorSecondary) {
+ textView.setTextColor(mThemedTextColorSecondary);
}
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
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 6999a9c..ae14fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -598,6 +598,7 @@
mKeyguardQsUserSwitchEnabled =
mKeyguardUserSwitcherEnabled && mResources.getBoolean(
R.bool.config_keyguard_user_switch_opens_qs_details);
+ keyguardUpdateMonitor.setKeyguardQsUserSwitchEnabled(mKeyguardQsUserSwitchEnabled);
mView.setWillNotDraw(!DEBUG);
mLayoutInflater = layoutInflater;
mFalsingManager = falsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index dacd941..9ee7b09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -27,6 +27,8 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
@@ -143,24 +145,14 @@
}
@Override
- public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
- boolean activityIn, boolean activityOut, String description, boolean isTransient,
- String statusLabel) {
+ public void setWifiIndicators(WifiIndicators indicators) {
if (DEBUG) {
- Log.d(TAG, "setWifiIndicators: "
- + "enabled = " + enabled + ","
- + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
- + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
- + "activityIn = " + activityIn + ","
- + "activityOut = " + activityOut + ","
- + "description = " + description + ","
- + "isTransient = " + isTransient + ","
- + "statusLabel = " + statusLabel);
+ Log.d(TAG, "setWifiIndicators: " + indicators);
}
- boolean visible = statusIcon.visible && !mHideWifi;
- boolean in = activityIn && mActivityEnabled && visible;
- boolean out = activityOut && mActivityEnabled && visible;
- mIsWifiEnabled = enabled;
+ boolean visible = indicators.statusIcon.visible && !mHideWifi;
+ boolean in = indicators.activityIn && mActivityEnabled && visible;
+ boolean out = indicators.activityOut && mActivityEnabled && visible;
+ mIsWifiEnabled = indicators.enabled;
WifiIconState newState = mWifiIconState.copy();
@@ -174,10 +166,10 @@
newState.resId = R.drawable.ic_qs_no_internet_available;
} else {
newState.visible = visible;
- newState.resId = statusIcon.icon;
+ newState.resId = indicators.statusIcon.icon;
newState.activityIn = in;
newState.activityOut = out;
- newState.contentDescription = statusIcon.contentDescription;
+ newState.contentDescription = indicators.statusIcon.contentDescription;
MobileIconState first = getFirstMobileState();
newState.signalSpacerVisible = first != null && first.typeId != 0;
}
@@ -225,44 +217,28 @@
}
@Override
- public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut,
- CharSequence typeContentDescription,
- CharSequence typeContentDescriptionHtml, CharSequence description,
- boolean isWide, int subId, boolean roaming, boolean showTriangle) {
+ public void setMobileDataIndicators(MobileDataIndicators indicators) {
if (DEBUG) {
- Log.d(TAG, "setMobileDataIndicators: "
- + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
- + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
- + "statusType = " + statusType + ","
- + "qsType = " + qsType + ","
- + "activityIn = " + activityIn + ","
- + "activityOut = " + activityOut + ","
- + "typeContentDescription = " + typeContentDescription + ","
- + "typeContentDescriptionHtml = " + typeContentDescriptionHtml + ","
- + "description = " + description + ","
- + "isWide = " + isWide + ","
- + "subId = " + subId + ","
- + "roaming = " + roaming + ","
- + "showTriangle = " + showTriangle);
+ Log.d(TAG, "setMobileDataIndicators: " + indicators);
}
- MobileIconState state = getState(subId);
+ MobileIconState state = getState(indicators.subId);
if (state == null) {
return;
}
// Visibility of the data type indicator changed
- boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
+ boolean typeChanged = indicators.statusType != state.typeId
+ && (indicators.statusType == 0 || state.typeId == 0);
- state.visible = statusIcon.visible && !mHideMobile;
- state.strengthId = statusIcon.icon;
- state.typeId = statusType;
- state.contentDescription = statusIcon.contentDescription;
- state.typeContentDescription = typeContentDescription;
- state.showTriangle = showTriangle;
- state.roaming = roaming;
- state.activityIn = activityIn && mActivityEnabled;
- state.activityOut = activityOut && mActivityEnabled;
+ state.visible = indicators.statusIcon.visible && !mHideMobile;
+ state.strengthId = indicators.statusIcon.icon;
+ state.typeId = indicators.statusType;
+ state.contentDescription = indicators.statusIcon.contentDescription;
+ state.typeContentDescription = indicators.typeContentDescription;
+ state.showTriangle = indicators.showTriangle;
+ state.roaming = indicators.roaming;
+ state.activityIn = indicators.activityIn && mActivityEnabled;
+ state.activityOut = indicators.activityOut && mActivityEnabled;
if (DEBUG) {
Log.d(TAG, "MobileIconStates: "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index 528c0cb..b96cb5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -23,7 +23,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -119,63 +121,29 @@
}
@Override
- public void setWifiIndicators(final boolean enabled, final IconState statusIcon,
- final IconState qsIcon, final boolean activityIn, final boolean activityOut,
- final String description, boolean isTransient, String secondaryLabel) {
+ public void setWifiIndicators(final WifiIndicators indicators) {
String log = new StringBuilder()
.append(SSDF.format(System.currentTimeMillis())).append(",")
- .append("setWifiIndicators: ")
- .append("enabled=").append(enabled).append(",")
- .append("statusIcon=").append(statusIcon).append(",")
- .append("qsIcon=").append(qsIcon).append(",")
- .append("activityIn=").append(activityIn).append(",")
- .append("activityOut=").append(activityOut).append(",")
- .append("description=").append(description).append(",")
- .append("isTransient=").append(isTransient).append(",")
- .append("secondaryLabel=").append(secondaryLabel)
+ .append(indicators)
.toString();
recordLastCallback(log);
post(() -> {
for (SignalCallback callback : mSignalCallbacks) {
- callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut,
- description, isTransient, secondaryLabel);
+ callback.setWifiIndicators(indicators);
}
});
-
-
}
@Override
- public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon,
- final int statusType, final int qsType, final boolean activityIn,
- final boolean activityOut, final CharSequence typeContentDescription,
- CharSequence typeContentDescriptionHtml, final CharSequence description,
- final boolean isWide, final int subId, boolean roaming, boolean showTriangle) {
+ public void setMobileDataIndicators(final MobileDataIndicators indicators) {
String log = new StringBuilder()
.append(SSDF.format(System.currentTimeMillis())).append(",")
- .append("setMobileDataIndicators: ")
- .append("statusIcon=").append(statusIcon).append(",")
- .append("qsIcon=").append(qsIcon).append(",")
- .append("statusType=").append(statusType).append(",")
- .append("qsType=").append(qsType).append(",")
- .append("activityIn=").append(activityIn).append(",")
- .append("activityOut=").append(activityOut).append(",")
- .append("typeContentDescription=").append(typeContentDescription).append(",")
- .append("typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
- .append(",")
- .append("description=").append(description).append(",")
- .append("isWide=").append(isWide).append(",")
- .append("subId=").append(subId).append(",")
- .append("roaming=").append(roaming).append(",")
- .append("showTriangle=").append(showTriangle)
+ .append(indicators)
.toString();
recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
- signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType,
- activityIn, activityOut, typeContentDescription,
- typeContentDescriptionHtml, description, isWide, subId, roaming,
- showTriangle);
+ signalCluster.setMobileDataIndicators(indicators);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
index a76d08a..7f935d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
@@ -16,17 +16,17 @@
package com.android.systemui.statusbar.policy;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
public interface IndividualSensorPrivacyController extends
CallbackController<IndividualSensorPrivacyController.Callback> {
void init();
- boolean isSensorBlocked(@IndividualSensor int sensor);
+ boolean isSensorBlocked(@Sensor int sensor);
- void setSensorBlocked(@IndividualSensor int sensor, boolean blocked);
+ void setSensorBlocked(@Sensor int sensor, boolean blocked);
interface Callback {
- void onSensorBlockedChanged(@IndividualSensor int sensor, boolean blocked);
+ void onSensorBlockedChanged(@Sensor int sensor, boolean blocked);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
index 32d15ed..295df05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.policy;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import android.hardware.SensorPrivacyManager;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.util.ArraySet;
import android.util.SparseBooleanArray;
@@ -30,8 +30,7 @@
public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
- private static final int[] SENSORS = new int[] {INDIVIDUAL_SENSOR_CAMERA,
- INDIVIDUAL_SENSOR_MICROPHONE};
+ private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
private final SparseBooleanArray mState = new SparseBooleanArray();
@@ -48,18 +47,18 @@
mSensorPrivacyManager.addSensorPrivacyListener(sensor,
(enabled) -> onSensorPrivacyChanged(sensor, enabled));
- mState.put(sensor, mSensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor));
+ mState.put(sensor, mSensorPrivacyManager.isSensorPrivacyEnabled(sensor));
}
}
@Override
- public boolean isSensorBlocked(@IndividualSensor int sensor) {
+ public boolean isSensorBlocked(@Sensor int sensor) {
return mState.get(sensor, false);
}
@Override
- public void setSensorBlocked(@IndividualSensor int sensor, boolean blocked) {
- mSensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, blocked);
+ public void setSensorBlocked(@Sensor int sensor, boolean blocked) {
+ mSensorPrivacyManager.setSensorPrivacyForProfileGroup(sensor, blocked);
}
@Override
@@ -72,7 +71,7 @@
mCallbacks.remove(listener);
}
- private void onSensorPrivacyChanged(@IndividualSensor int sensor, boolean blocked) {
+ private void onSensorPrivacyChanged(@Sensor int sensor, boolean blocked) {
mState.put(sensor, blocked);
for (Callback callback : mCallbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
index 4f69cd6..4e5c461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 1ab7652..6c097bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -59,6 +59,7 @@
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.io.PrintWriter;
@@ -402,10 +403,12 @@
showDataIcon |= mCurrentState.roaming;
IconState statusIcon = new IconState(showDataIcon && !mCurrentState.airplaneMode,
getCurrentIconId(), contentDescription);
- callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+ MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
+ statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, dataContentDescriptionHtml,
description, icons.isWide, mSubscriptionInfo.getSubscriptionId(),
mCurrentState.roaming, showTriangle);
+ callback.setMobileDataIndicators(mobileDataIndicators);
} else {
boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
IconState statusIcon = new IconState(
@@ -432,10 +435,12 @@
showDataIcon &= mCurrentState.isDefault || dataDisabled;
int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.dataType : 0;
boolean showTriangle = mCurrentState.enabled && !mCurrentState.airplaneMode;
- callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+ MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
+ statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, dataContentDescriptionHtml,
description, icons.isWide, mSubscriptionInfo.getSubscriptionId(),
mCurrentState.roaming, showTriangle);
+ callback.setMobileDataIndicators(mobileDataIndicators);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 0a9fead..ef2ca98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -46,34 +46,117 @@
boolean isRadioOn();
+ /**
+ * Wrapper class for all the WiFi signals used for WiFi indicators.
+ */
+ final class WifiIndicators {
+ public boolean enabled;
+ public IconState statusIcon;
+ public IconState qsIcon;
+ public boolean activityIn;
+ public boolean activityOut;
+ public String description;
+ public boolean isTransient;
+ public String statusLabel;
+
+ public WifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description,
+ boolean isTransient, String statusLabel) {
+ this.enabled = enabled;
+ this.statusIcon = statusIcon;
+ this.qsIcon = qsIcon;
+ this.activityIn = activityIn;
+ this.activityOut = activityOut;
+ this.description = description;
+ this.isTransient = isTransient;
+ this.statusLabel = statusLabel;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("WifiIndicators[")
+ .append("enabled=").append(enabled)
+ .append(",statusIcon=").append(statusIcon == null ? "" : statusIcon.toString())
+ .append(",qsIcon=").append(qsIcon == null ? "" : qsIcon.toString())
+ .append(",activityIn=").append(activityIn)
+ .append(",activityOut=").append(activityOut)
+ .append(",description=").append(description)
+ .append(",isTransient=").append(isTransient)
+ .append(",statusLabel=").append(statusLabel)
+ .append(']').toString();
+ }
+ }
+
+ /**
+ * Wrapper class for all the mobile signals used for mobile data indicators.
+ */
+ final class MobileDataIndicators {
+ public IconState statusIcon;
+ public IconState qsIcon;
+ public int statusType;
+ public int qsType;
+ public boolean activityIn;
+ public boolean activityOut;
+ public CharSequence typeContentDescription;
+ public CharSequence typeContentDescriptionHtml;
+ public CharSequence description;
+ public boolean isWide;
+ public int subId;
+ public boolean roaming;
+ public boolean showTriangle;
+
+ public MobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
+ int qsType, boolean activityIn, boolean activityOut,
+ CharSequence typeContentDescription, CharSequence typeContentDescriptionHtml,
+ CharSequence description, boolean isWide, int subId, boolean roaming,
+ boolean showTriangle) {
+ this.statusIcon = statusIcon;
+ this.qsIcon = qsIcon;
+ this.statusType = statusType;
+ this.qsType = qsType;
+ this.activityIn = activityIn;
+ this.activityOut = activityOut;
+ this.typeContentDescription = typeContentDescription;
+ this.typeContentDescriptionHtml = typeContentDescriptionHtml;
+ this.description = description;
+ this.isWide = isWide;
+ this.subId = subId;
+ this.roaming = roaming;
+ this.showTriangle = showTriangle;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("MobileDataIndicators[")
+ .append("statusIcon=").append(statusIcon == null ? "" : statusIcon.toString())
+ .append(",qsIcon=").append(qsIcon == null ? "" : qsIcon.toString())
+ .append(",statusType=").append(statusType)
+ .append(",qsType=").append(qsType)
+ .append(",activityIn=").append(activityIn)
+ .append(",activityOut=").append(activityOut)
+ .append(",typeContentDescription=").append(typeContentDescription)
+ .append(",typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
+ .append(",description=").append(description)
+ .append(",isWide=").append(isWide)
+ .append(",subId=").append(subId)
+ .append(",roaming=").append(roaming)
+ .append(",showTriangle=").append(showTriangle)
+ .append(']').toString();
+ }
+ }
+
public interface SignalCallback {
- default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
- boolean activityIn, boolean activityOut, String description, boolean isTransient,
- String statusLabel) {}
+ /**
+ * Callback for listeners to be able to update the state of any UI tracking connectivity of
+ * WiFi networks.
+ */
+ default void setWifiIndicators(WifiIndicators wifiIndicators) {}
/**
* Callback for listeners to be able to update the state of any UI tracking connectivity
- * @param statusIcon the icon that should be shown in the status bar
- * @param qsIcon the icon to show in Quick Settings
- * @param statusType the resId of the data type icon (e.g. LTE) to show in the status bar
- * @param qsType similar to above, the resId of the data type icon to show in Quick Settings
- * @param activityIn indicates whether there is inbound activity
- * @param activityOut indicates outbound activity
- * @param typeContentDescription the contentDescription of the data type
- * @param typeContentDescriptionHtml the (possibly HTML-styled) contentDescription of the
- * data type. Suitable for display
- * @param description description of the network (usually just the network name)
- * @param isWide //TODO: unused?
- * @param subId subscription ID for which to update the UI
- * @param roaming indicates roaming
- * @param showTriangle whether to show the mobile triangle the in status bar
+ * of Mobile networks.
*/
- default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut,
- CharSequence typeContentDescription,
- CharSequence typeContentDescriptionHtml, CharSequence description,
- boolean isWide, int subId, boolean roaming, boolean showTriangle) {
- }
+ default void setMobileDataIndicators(MobileDataIndicators mobileDataIndicators) {}
default void setSubs(List<SubscriptionInfo> subs) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9f92142..8eb1e64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -165,7 +165,7 @@
private int mCurrentUserId;
private OnSubscriptionsChangedListener mSubscriptionListener;
-
+ private NetworkCapabilities mLastDefaultNetworkCapabilities;
// Handler that all broadcasts are received on.
private final Handler mReceiverHandler;
// Handler that all callbacks are made on.
@@ -315,6 +315,7 @@
public void onLost(Network network) {
mLastNetwork = null;
mLastNetworkCapabilities = null;
+ mLastDefaultNetworkCapabilities = null;
String callback = new StringBuilder()
.append(SSDF.format(System.currentTimeMillis())).append(",")
.append("onLost: ")
@@ -341,6 +342,7 @@
}
mLastNetwork = network;
mLastNetworkCapabilities = networkCapabilities;
+ mLastDefaultNetworkCapabilities = networkCapabilities;
String callback = new StringBuilder()
.append(SSDF.format(System.currentTimeMillis())).append(",")
.append("onCapabilitiesChanged: ")
@@ -959,18 +961,17 @@
private void updateConnectivity() {
mConnectedTransports.clear();
mValidatedTransports.clear();
- for (NetworkCapabilities nc :
- mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
- for (int transportType : nc.getTransportTypes()) {
+ if (mLastDefaultNetworkCapabilities != null) {
+ for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) {
if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR
- && Utils.tryGetWifiInfoForVcn(nc) != null) {
+ && Utils.tryGetWifiInfoForVcn(mLastDefaultNetworkCapabilities) != null) {
mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
- if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
+ if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
mValidatedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
}
} else {
mConnectedTransports.set(transportType);
- if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
+ if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
mValidatedTransports.set(transportType);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 16998d7..8d72c9c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -38,7 +38,9 @@
import com.android.settingslib.wifi.WifiStatusTracker;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import java.io.PrintWriter;
import java.util.Objects;
@@ -113,18 +115,24 @@
mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
: getQsCurrentIconId(), contentDescription);
}
- callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+ WifiIndicators wifiIndicators = new WifiIndicators(
+ mCurrentState.enabled, statusIcon, qsIcon,
ssidPresent && mCurrentState.activityIn,
ssidPresent && mCurrentState.activityOut,
- wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
+ wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel
+ );
+ callback.setWifiIndicators(wifiIndicators);
} else {
IconState qsIcon = new IconState(mCurrentState.connected,
mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
: getQsCurrentIconId(), contentDescription);
- callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+ WifiIndicators wifiIndicators = new WifiIndicators(
+ mCurrentState.enabled, statusIcon, qsIcon,
ssidPresent && mCurrentState.activityIn,
ssidPresent && mCurrentState.activityOut,
- wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
+ wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel
+ );
+ callback.setWifiIndicators(wifiIndicators);
}
}
@@ -149,10 +157,13 @@
mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(), contentDescription);
CharSequence description =
mNetworkController.getNetworkNameForCarrierWiFi(mCurrentState.subId);
- callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+ MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
+ statusIcon, qsIcon, typeIcon, qsTypeIcon,
mCurrentState.activityIn, mCurrentState.activityOut, dataContentDescription,
dataContentDescriptionHtml, description, icons.isWide,
- mCurrentState.subId, /* roaming= */ false, /* showTriangle= */ true);
+ mCurrentState.subId, /* roaming= */ false, /* showTriangle= */ true
+ );
+ callback.setMobileDataIndicators(mobileDataIndicators);
}
private int getCurrentIconIdForCarrierWifi() {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index 9effc67..bbb2f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -161,10 +161,10 @@
void applyCurrentUserOverlays(
Map<String, OverlayIdentifier> categoryToPackage,
FabricatedOverlay[] pendingCreation,
- Set<UserHandle> userHandles) {
+ int currentUser,
+ Set<UserHandle> managedProfiles) {
// Disable all overlays that have not been specified in the user setting.
final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES);
- overlayCategoriesToDisable.removeAll(categoryToPackage.keySet());
final Set<String> targetPackagesToQuery = overlayCategoriesToDisable.stream()
.map(category -> mCategoryToTargetPackage.get(category))
.collect(Collectors.toSet());
@@ -175,6 +175,7 @@
.filter(o ->
mTargetPackageToCategories.get(o.targetPackageName).contains(o.category))
.filter(o -> overlayCategoriesToDisable.contains(o.category))
+ .filter(o -> !categoryToPackage.containsValue(new OverlayIdentifier(o.packageName)))
.filter(o -> o.isEnabled())
.map(o -> new Pair<>(o.category, o.packageName))
.collect(Collectors.toList());
@@ -186,17 +187,18 @@
}
}
- // Toggle overlays in the order of THEME_CATEGORIES.
+ for (Pair<String, String> packageToDisable : overlaysToDisable) {
+ OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second);
+ setEnabled(transaction, overlayInfo, packageToDisable.first, currentUser,
+ managedProfiles, false);
+ }
+
for (String category : THEME_CATEGORIES) {
if (categoryToPackage.containsKey(category)) {
OverlayIdentifier overlayInfo = categoryToPackage.get(category);
- setEnabled(transaction, overlayInfo, category, userHandles, true);
+ setEnabled(transaction, overlayInfo, category, currentUser, managedProfiles, true);
}
}
- for (Pair<String, String> packageToDisable : overlaysToDisable) {
- OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second);
- setEnabled(transaction, overlayInfo, packageToDisable.first, userHandles, false);
- }
mExecutor.execute(() -> {
try {
@@ -213,18 +215,30 @@
}
private void setEnabled(OverlayManagerTransaction.Builder transaction,
- OverlayIdentifier identifier, String category, Set<UserHandle> handles,
- boolean enabled) {
+ OverlayIdentifier identifier, String category, int currentUser,
+ Set<UserHandle> managedProfiles, boolean enabled) {
if (DEBUG) {
Log.d(TAG, "setEnabled: " + identifier.getPackageName() + " category: "
+ category + ": " + enabled);
}
- for (UserHandle userHandle : handles) {
- transaction.setEnabled(identifier, enabled, userHandle.getIdentifier());
- }
- if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) {
+
+ transaction.setEnabled(identifier, enabled, currentUser);
+ if (currentUser != UserHandle.SYSTEM.getIdentifier()
+ && SYSTEM_USER_CATEGORIES.contains(category)) {
transaction.setEnabled(identifier, enabled, UserHandle.SYSTEM.getIdentifier());
}
+
+ // Do not apply Launcher or Theme picker overlays to managed users. Apps are not
+ // installed in there.
+ OverlayInfo overlayInfo = mOverlayManager.getOverlayInfo(identifier, UserHandle.SYSTEM);
+ if (overlayInfo == null || overlayInfo.targetPackageName.equals(mLauncherPackage)
+ || overlayInfo.targetPackageName.equals(mThemePickerPackage)) {
+ return;
+ }
+
+ for (UserHandle userHandle : managedProfiles) {
+ transaction.setEnabled(identifier, enabled, userHandle.getIdentifier());
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 028cbd0..5d02845 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -55,14 +55,13 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
-import com.google.android.collect.Sets;
-
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -151,7 +150,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
- updateThemeOverlays();
+ reevaluateSystemTheme(true /* forceReload */);
}
}, filter, mBgExecutor, UserHandle.ALL);
mSecureSettings.registerContentObserverForUser(
@@ -163,7 +162,7 @@
int userId) {
if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
if (ActivityManager.getCurrentUser() == userId) {
- updateThemeOverlays();
+ reevaluateSystemTheme(true /* forceReload */);
}
}
},
@@ -180,7 +179,7 @@
mLockColors = lockColors;
}
mSystemColors = systemColor;
- reevaluateSystemTheme();
+ reevaluateSystemTheme(false /* forceReload */);
});
});
if (USE_LOCK_SCREEN_WALLPAPER) {
@@ -192,7 +191,7 @@
}
// It's possible that the user has a lock screen wallpaper. On this case we'll
// end up with different colors after unlocking.
- reevaluateSystemTheme();
+ reevaluateSystemTheme(false /* forceReload */);
}
});
}
@@ -209,11 +208,11 @@
Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
}
}
- reevaluateSystemTheme();
+ reevaluateSystemTheme(false /* forceReload */);
}, null, UserHandle.USER_ALL);
}
- private void reevaluateSystemTheme() {
+ private void reevaluateSystemTheme(boolean forceReload) {
WallpaperColors currentColors =
mKeyguardStateController.isShowing() && mLockColors != null
? mLockColors : mSystemColors;
@@ -228,7 +227,8 @@
accentCandidate = getAccentColor(currentColors);
}
- if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate) {
+ if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate
+ && !forceReload) {
return;
}
@@ -309,6 +309,16 @@
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName());
}
+ } else if (!mIsMonetEnabled && systemPalette != null) {
+ try {
+ // It's possible that we flipped the flag off and still have a @ColorInt in the
+ // setting. We need to sanitize the input, otherwise the overlay transaction will
+ // fail.
+ Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16);
+ categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
+ } catch (NumberFormatException e) {
+ // This is a package name. All good, let's continue
+ }
}
// Same for accent color.
@@ -322,6 +332,13 @@
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName());
}
+ } else if (!mIsMonetEnabled && accentPalette != null) {
+ try {
+ Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16);
+ categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
+ } catch (NumberFormatException e) {
+ // This is a package name. All good, let's continue
+ }
}
// Compatibility with legacy themes, where full packages were defined, instead of just
@@ -337,10 +354,10 @@
categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mSecondaryOverlay.getIdentifier());
}
- Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
+ Set<UserHandle> managedProfiles = new HashSet<>();
for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
if (userInfo.isManagedProfile()) {
- userHandles.add(userInfo.getUserHandle());
+ managedProfiles.add(userInfo.getUserHandle());
}
}
if (DEBUG) {
@@ -352,9 +369,10 @@
mNeedsOverlayCreation = false;
mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
mPrimaryOverlay, mSecondaryOverlay, mNeutralOverlay
- }, userHandles);
+ }, currentUser, managedProfiles);
} else {
- mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, userHandles);
+ mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
+ managedProfiles);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index df54eab..25345d5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -33,7 +33,11 @@
import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Dialog;
@@ -51,6 +55,9 @@
import android.graphics.PixelFormat;
import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.RotateDrawable;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.os.Debug;
@@ -81,6 +88,8 @@
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
@@ -88,6 +97,7 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
@@ -99,6 +109,8 @@
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.AlphaTintDrawableWrapper;
+import com.android.systemui.util.RoundedCornerProgressDrawable;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -124,8 +136,14 @@
static final int DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS = 5000;
static final int DIALOG_HOVERING_TIMEOUT_MILLIS = 16000;
+ private static final int DRAWER_ANIMATION_DURATION_SHORT = 175;
+ private static final int DRAWER_ANIMATION_DURATION = 250;
+
private final int mDialogShowAnimationDurationMs;
private final int mDialogHideAnimationDurationMs;
+ private final int mRingerDrawerItemSize;
+ private final boolean mShowVibrate;
+ private final int mRingerCount;
private final boolean mShowLowMediaVolumeIcon;
private final boolean mChangeVolumeRowTintWhenInactive;
@@ -140,6 +158,30 @@
private ViewGroup mDialogView;
private ViewGroup mDialogRowsView;
private ViewGroup mRinger;
+
+ private ViewGroup mSelectedRingerContainer;
+ private ImageView mSelectedRingerIcon;
+
+ private ViewGroup mRingerDrawerContainer;
+ private ViewGroup mRingerDrawerMute;
+ private ViewGroup mRingerDrawerVibrate;
+ private ViewGroup mRingerDrawerNormal;
+ private ImageView mRingerDrawerMuteIcon;
+ private ImageView mRingerDrawerVibrateIcon;
+ private ImageView mRingerDrawerNormalIcon;
+
+ /**
+ * View that draws the 'selected' background behind one of the three ringer choices in the
+ * drawer.
+ */
+ private ViewGroup mRingerDrawerNewSelectionBg;
+
+ private final ValueAnimator mRingerDrawerIconColorAnimator = ValueAnimator.ofFloat(0f, 1f);
+ private ImageView mRingerDrawerIconAnimatingSelected;
+ private ImageView mRingerDrawerIconAnimatingDeselected;
+
+ private boolean mIsRingerDrawerOpen = false;
+
private ImageButton mRingerIcon;
private ViewGroup mODICaptionsView;
private CaptionsToggleImageButton mODICaptionsIcon;
@@ -191,6 +233,12 @@
mContext.getResources().getInteger(R.integer.config_dialogShowAnimationDurationMs);
mDialogHideAnimationDurationMs =
mContext.getResources().getInteger(R.integer.config_dialogHideAnimationDurationMs);
+ mRingerDrawerItemSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.volume_ringer_drawer_item_size);
+ mShowVibrate = mController.hasVibrator();
+
+ // Normal, mute, and possibly vibrate.
+ mRingerCount = mShowVibrate ? 3 : 2;
}
@Override
@@ -314,6 +362,20 @@
mZenIcon = mRinger.findViewById(R.id.dnd_icon);
}
+ mSelectedRingerIcon = mDialog.findViewById(R.id.volume_new_ringer_active_icon);
+ mSelectedRingerContainer = mDialog.findViewById(
+ R.id.volume_new_ringer_active_icon_container);
+
+ mRingerDrawerMute = mDialog.findViewById(R.id.volume_drawer_mute);
+ mRingerDrawerNormal = mDialog.findViewById(R.id.volume_drawer_normal);
+ mRingerDrawerVibrate = mDialog.findViewById(R.id.volume_drawer_vibrate);
+ mRingerDrawerMuteIcon = mDialog.findViewById(R.id.volume_drawer_mute_icon);
+ mRingerDrawerVibrateIcon = mDialog.findViewById(R.id.volume_drawer_vibrate_icon);
+ mRingerDrawerNormalIcon = mDialog.findViewById(R.id.volume_drawer_normal_icon);
+ mRingerDrawerNewSelectionBg = mDialog.findViewById(R.id.volume_drawer_selection_background);
+
+ setupRingerDrawer();
+
mODICaptionsView = mDialog.findViewById(R.id.odi_captions);
if (mODICaptionsView != null) {
mODICaptionsIcon = mODICaptionsView.findViewById(R.id.odi_captions_icon);
@@ -475,40 +537,275 @@
row.anim = null;
+ final LayerDrawable seekbarDrawable =
+ (LayerDrawable) mContext.getDrawable(R.drawable.volume_row_seekbar);
+
+ final LayerDrawable seekbarBgDrawable =
+ (LayerDrawable) seekbarDrawable.findDrawableByLayerId(android.R.id.background);
+
+ row.sliderBgSolid = seekbarBgDrawable.findDrawableByLayerId(
+ R.id.volume_seekbar_background_solid);
+
+ row.sliderBgIcon = (AlphaTintDrawableWrapper)
+ ((RotateDrawable) seekbarBgDrawable.findDrawableByLayerId(
+ R.id.volume_seekbar_background_icon)).getDrawable();
+
+ final LayerDrawable seekbarProgressDrawable = (LayerDrawable)
+ ((RoundedCornerProgressDrawable) seekbarDrawable.findDrawableByLayerId(
+ android.R.id.progress)).getDrawable();
+
+ row.sliderProgressSolid = seekbarProgressDrawable.findDrawableByLayerId(
+ R.id.volume_seekbar_progress_solid);
+
+ row.sliderProgressIcon = (AlphaTintDrawableWrapper)
+ ((RotateDrawable) seekbarProgressDrawable.findDrawableByLayerId(
+ R.id.volume_seekbar_progress_icon)).getDrawable();
+
+ row.slider.setProgressDrawable(seekbarDrawable);
+ row.slider.setThumb(null);
+
row.icon = row.view.findViewById(R.id.volume_row_icon);
- row.icon.setImageResource(iconRes);
- if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
- row.icon.setOnClickListener(v -> {
- Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState);
- mController.setActiveStream(row.stream);
- if (row.stream == AudioManager.STREAM_RING) {
- final boolean hasVibrator = mController.hasVibrator();
- if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
- if (hasVibrator) {
- mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+
+ row.setIcon(iconRes, mContext.getTheme());
+
+ if (row.icon != null) {
+ if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
+ row.icon.setOnClickListener(v -> {
+ Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState);
+ mController.setActiveStream(row.stream);
+ if (row.stream == AudioManager.STREAM_RING) {
+ final boolean hasVibrator = mController.hasVibrator();
+ if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
+ if (hasVibrator) {
+ mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+ } else {
+ final boolean wasZero = row.ss.level == 0;
+ mController.setStreamVolume(stream,
+ wasZero ? row.lastAudibleLevel : 0);
+ }
} else {
- final boolean wasZero = row.ss.level == 0;
- mController.setStreamVolume(stream,
- wasZero ? row.lastAudibleLevel : 0);
+ mController.setRingerMode(
+ AudioManager.RINGER_MODE_NORMAL, false);
+ if (row.ss.level == 0) {
+ mController.setStreamVolume(stream, 1);
+ }
}
} else {
- mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
- if (row.ss.level == 0) {
- mController.setStreamVolume(stream, 1);
- }
+ final boolean vmute = row.ss.level == row.ss.levelMin;
+ mController.setStreamVolume(stream,
+ vmute ? row.lastAudibleLevel : row.ss.levelMin);
}
- } else {
- final boolean vmute = row.ss.level == row.ss.levelMin;
- mController.setStreamVolume(stream,
- vmute ? row.lastAudibleLevel : row.ss.levelMin);
- }
- row.userAttempt = 0; // reset the grace period, slider updates immediately
- });
- } else {
- row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ row.userAttempt = 0; // reset the grace period, slider updates immediately
+ });
+ } else {
+ row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ }
}
}
+ private void setRingerMode(int newRingerMode) {
+ Events.writeEvent(Events.EVENT_RINGER_TOGGLE, newRingerMode);
+ incrementManualToggleCount();
+ updateRingerH();
+ provideTouchFeedbackH(newRingerMode);
+ mController.setRingerMode(newRingerMode, false);
+ maybeShowToastH(newRingerMode);
+ }
+
+ private void setupRingerDrawer() {
+ mRingerDrawerContainer = mDialog.findViewById(R.id.volume_drawer_container);
+
+ if (mRingerDrawerContainer == null) {
+ return;
+ }
+
+ if (!mShowVibrate) {
+ mRingerDrawerVibrate.setVisibility(GONE);
+ }
+
+ // In portrait, add padding to the bottom to account for the height of the open ringer
+ // drawer.
+ if (!isLandscape()) {
+ mDialogView.setPadding(
+ mDialogView.getPaddingLeft(),
+ mDialogView.getPaddingTop(),
+ mDialogView.getPaddingRight(),
+ mDialogView.getPaddingBottom() + (mRingerCount - 1) * mRingerDrawerItemSize);
+ } else {
+ mDialogView.setPadding(
+ mDialogView.getPaddingLeft() + (mRingerCount - 1) * mRingerDrawerItemSize,
+ mDialogView.getPaddingTop(),
+ mDialogView.getPaddingRight(),
+ mDialogView.getPaddingBottom());
+ }
+
+ ((LinearLayout) mRingerDrawerContainer.findViewById(R.id.volume_drawer_options))
+ .setOrientation(isLandscape() ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
+
+ mSelectedRingerContainer.setOnClickListener(view -> {
+ if (mIsRingerDrawerOpen) {
+ hideRingerDrawer();
+ } else {
+ showRingerDrawer();
+ }
+ });
+
+ mRingerDrawerVibrate.setOnClickListener(
+ new RingerDrawerItemClickListener(RINGER_MODE_VIBRATE));
+ mRingerDrawerMute.setOnClickListener(
+ new RingerDrawerItemClickListener(RINGER_MODE_SILENT));
+ mRingerDrawerNormal.setOnClickListener(
+ new RingerDrawerItemClickListener(RINGER_MODE_NORMAL));
+
+ final int unselectedColor = Utils.getColorAccentDefaultColor(mContext);
+ final int selectedColor = Utils.getColorAttrDefaultColor(
+ mContext, android.R.attr.colorBackgroundFloating);
+
+ // Add an update listener that animates the deselected icon to the unselected color, and the
+ // selected icon to the selected color.
+ mRingerDrawerIconColorAnimator.addUpdateListener(
+ anim -> {
+ final float currentValue = (float) anim.getAnimatedValue();
+ final int curUnselectedColor = (int) ArgbEvaluator.getInstance().evaluate(
+ currentValue, selectedColor, unselectedColor);
+ final int curSelectedColor = (int) ArgbEvaluator.getInstance().evaluate(
+ currentValue, unselectedColor, selectedColor);
+
+ mRingerDrawerIconAnimatingDeselected.setColorFilter(curUnselectedColor);
+ mRingerDrawerIconAnimatingSelected.setColorFilter(curSelectedColor);
+ });
+ mRingerDrawerIconColorAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mRingerDrawerIconAnimatingDeselected.clearColorFilter();
+ mRingerDrawerIconAnimatingSelected.clearColorFilter();
+ }
+ });
+ mRingerDrawerIconColorAnimator.setDuration(DRAWER_ANIMATION_DURATION_SHORT);
+ }
+
+ private ImageView getDrawerIconViewForMode(int mode) {
+ if (mode == RINGER_MODE_VIBRATE) {
+ return mRingerDrawerVibrateIcon;
+ } else if (mode == RINGER_MODE_SILENT) {
+ return mRingerDrawerMuteIcon;
+ } else {
+ return mRingerDrawerNormalIcon;
+ }
+ }
+
+ /**
+ * Translation to apply form the origin (either top or left) to overlap the selection background
+ * with the given mode in the drawer.
+ */
+ private float getTranslationInDrawerForRingerMode(int mode) {
+ return mode == RINGER_MODE_VIBRATE
+ ? -mRingerDrawerItemSize * 2
+ : mode == RINGER_MODE_SILENT
+ ? -mRingerDrawerItemSize
+ : 0;
+ }
+
+ /** Animates in the ringer drawer. */
+ private void showRingerDrawer() {
+ // Show all ringer icons except the currently selected one, since we're going to animate the
+ // ringer button to that position.
+ mRingerDrawerVibrateIcon.setVisibility(
+ mState.ringerModeInternal == RINGER_MODE_VIBRATE ? INVISIBLE : VISIBLE);
+ mRingerDrawerMuteIcon.setVisibility(
+ mState.ringerModeInternal == RINGER_MODE_SILENT ? INVISIBLE : VISIBLE);
+ mRingerDrawerNormalIcon.setVisibility(
+ mState.ringerModeInternal == RINGER_MODE_NORMAL ? INVISIBLE : VISIBLE);
+
+ // Hide the selection background - we use this to show a selection when one is
+ // tapped, so it should be invisible until that happens. However, position it below
+ // the currently selected ringer so that it's ready to animate.
+ mRingerDrawerNewSelectionBg.setAlpha(0f);
+
+ if (!isLandscape()) {
+ mRingerDrawerNewSelectionBg.setTranslationY(
+ getTranslationInDrawerForRingerMode(mState.ringerModeInternal));
+ } else {
+ mRingerDrawerNewSelectionBg.setTranslationX(
+ getTranslationInDrawerForRingerMode(mState.ringerModeInternal));
+ }
+
+ // Move the drawer so that the top/rightmost ringer choice overlaps with the selected ringer
+ // icon.
+ if (!isLandscape()) {
+ mRingerDrawerContainer.setTranslationY(mRingerDrawerItemSize * (mRingerCount - 1));
+ } else {
+ mRingerDrawerContainer.setTranslationX(mRingerDrawerItemSize * (mRingerCount - 1));
+ }
+ mRingerDrawerContainer.setAlpha(0f);
+ mRingerDrawerContainer.setVisibility(VISIBLE);
+
+ // Animate the drawer up and visible.
+ mRingerDrawerContainer.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ // Vibrate is way farther up, so give the selected ringer icon a head start if
+ // vibrate is selected.
+ .setDuration(mState.ringerModeInternal == RINGER_MODE_VIBRATE
+ ? DRAWER_ANIMATION_DURATION_SHORT
+ : DRAWER_ANIMATION_DURATION)
+ .setStartDelay(mState.ringerModeInternal == RINGER_MODE_VIBRATE
+ ? DRAWER_ANIMATION_DURATION - DRAWER_ANIMATION_DURATION_SHORT
+ : 0)
+ .alpha(1f)
+ .translationX(0f)
+ .translationY(0f)
+ .start();
+
+ // Animate the selected ringer view up to that ringer's position in the drawer.
+ mSelectedRingerContainer.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(DRAWER_ANIMATION_DURATION)
+ .withEndAction(() ->
+ getDrawerIconViewForMode(mState.ringerModeInternal).setVisibility(VISIBLE));
+
+ if (!isLandscape()) {
+ mSelectedRingerContainer.animate()
+ .translationY(getTranslationInDrawerForRingerMode(mState.ringerModeInternal))
+ .start();
+ } else {
+ mSelectedRingerContainer.animate()
+ .translationX(getTranslationInDrawerForRingerMode(mState.ringerModeInternal))
+ .start();
+ }
+
+ mIsRingerDrawerOpen = true;
+ }
+
+ /** Animates away the ringer drawer. */
+ private void hideRingerDrawer() {
+ // Hide the drawer icon for the selected ringer - it's visible in the ringer button and we
+ // don't want to be able to see it while it animates away.
+ getDrawerIconViewForMode(mState.ringerModeInternal).setVisibility(INVISIBLE);
+
+ mRingerDrawerContainer.animate()
+ .alpha(0f)
+ .setDuration(DRAWER_ANIMATION_DURATION)
+ .setStartDelay(0)
+ .withEndAction(() -> mRingerDrawerContainer.setVisibility(INVISIBLE));
+
+ if (!isLandscape()) {
+ mRingerDrawerContainer.animate()
+ .translationY(mRingerDrawerItemSize * 2)
+ .start();
+ } else {
+ mRingerDrawerContainer.animate()
+ .translationX(mRingerDrawerItemSize * 2)
+ .start();
+ }
+
+ mSelectedRingerContainer.animate()
+ .translationX(0f)
+ .translationY(0f)
+ .start();
+
+ mIsRingerDrawerOpen = false;
+ }
+
public void initSettingsH() {
if (mSettingsView != null) {
mSettingsView.setVisibility(
@@ -555,12 +852,8 @@
mController.setStreamVolume(AudioManager.STREAM_RING, 1);
}
}
- Events.writeEvent(Events.EVENT_RINGER_TOGGLE, newRingerMode);
- incrementManualToggleCount();
- updateRingerH();
- provideTouchFeedbackH(newRingerMode);
- mController.setRingerMode(newRingerMode, false);
- maybeShowToastH(newRingerMode);
+
+ setRingerMode(newRingerMode);
});
}
updateRingerH();
@@ -809,6 +1102,8 @@
mDialog.dismiss();
tryToRemoveCaptionsTooltip();
mIsAnimatingDismiss = false;
+
+ hideRingerDrawer();
}, 50));
if (!isLandscape()) animator.translationX(mDialogView.getWidth() / 2.0f);
animator.start();
@@ -889,12 +1184,14 @@
switch (mState.ringerModeInternal) {
case AudioManager.RINGER_MODE_VIBRATE:
mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
+ mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
addAccessibilityDescription(mRingerIcon, RINGER_MODE_VIBRATE,
mContext.getString(R.string.volume_ringer_hint_mute));
mRingerIcon.setTag(Events.ICON_STATE_VIBRATE);
break;
case AudioManager.RINGER_MODE_SILENT:
mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+ mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
mRingerIcon.setTag(Events.ICON_STATE_MUTE);
addAccessibilityDescription(mRingerIcon, RINGER_MODE_SILENT,
mContext.getString(R.string.volume_ringer_hint_unmute));
@@ -904,11 +1201,13 @@
boolean muted = (mAutomute && ss.level == 0) || ss.muted;
if (!isZenMuted && muted) {
mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+ mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL,
mContext.getString(R.string.volume_ringer_hint_unmute));
mRingerIcon.setTag(Events.ICON_STATE_MUTE);
} else {
mRingerIcon.setImageResource(R.drawable.ic_volume_ringer);
+ mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer);
if (mController.hasVibrator()) {
addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL,
mContext.getString(R.string.volume_ringer_hint_vibrate));
@@ -1075,8 +1374,6 @@
// update icon
final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
- row.icon.setEnabled(iconEnabled);
- row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
final int iconRes;
if (isRingVibrate) {
iconRes = R.drawable.ic_volume_ringer_vibrate;
@@ -1092,7 +1389,7 @@
? R.drawable.ic_volume_media_low : row.iconRes;
}
- row.icon.setImageResource(iconRes);
+ row.setIcon(iconRes, mContext.getTheme());
row.iconState =
iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
: (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
@@ -1101,18 +1398,35 @@
|| iconRes == R.drawable.ic_volume_media_low)
? Events.ICON_STATE_UNMUTE
: Events.ICON_STATE_UNKNOWN;
- if (iconEnabled) {
- if (isRingStream) {
- if (isRingVibrate) {
- row.icon.setContentDescription(mContext.getString(
- R.string.volume_stream_content_description_unmute,
- getStreamLabelH(ss)));
- } else {
- if (mController.hasVibrator()) {
+
+ if (row.icon != null) {
+ if (iconEnabled) {
+ if (isRingStream) {
+ if (isRingVibrate) {
row.icon.setContentDescription(mContext.getString(
- mShowA11yStream
- ? R.string.volume_stream_content_description_vibrate_a11y
- : R.string.volume_stream_content_description_vibrate,
+ R.string.volume_stream_content_description_unmute,
+ getStreamLabelH(ss)));
+ } else {
+ if (mController.hasVibrator()) {
+ row.icon.setContentDescription(mContext.getString(
+ mShowA11yStream
+ ? R.string.volume_stream_content_description_vibrate_a11y
+ : R.string.volume_stream_content_description_vibrate,
+ getStreamLabelH(ss)));
+ } else {
+ row.icon.setContentDescription(mContext.getString(
+ mShowA11yStream
+ ? R.string.volume_stream_content_description_mute_a11y
+ : R.string.volume_stream_content_description_mute,
+ getStreamLabelH(ss)));
+ }
+ }
+ } else if (isA11yStream) {
+ row.icon.setContentDescription(getStreamLabelH(ss));
+ } else {
+ if (ss.muted || mAutomute && ss.level == 0) {
+ row.icon.setContentDescription(mContext.getString(
+ R.string.volume_stream_content_description_unmute,
getStreamLabelH(ss)));
} else {
row.icon.setContentDescription(mContext.getString(
@@ -1122,23 +1436,9 @@
getStreamLabelH(ss)));
}
}
- } else if (isA11yStream) {
- row.icon.setContentDescription(getStreamLabelH(ss));
} else {
- if (ss.muted || mAutomute && ss.level == 0) {
- row.icon.setContentDescription(mContext.getString(
- R.string.volume_stream_content_description_unmute,
- getStreamLabelH(ss)));
- } else {
- row.icon.setContentDescription(mContext.getString(
- mShowA11yStream
- ? R.string.volume_stream_content_description_mute_a11y
- : R.string.volume_stream_content_description_mute,
- getStreamLabelH(ss)));
- }
+ row.icon.setContentDescription(getStreamLabelH(ss));
}
- } else {
- row.icon.setContentDescription(getStreamLabelH(ss));
}
// ensure tracking is disabled if zenMuted
@@ -1167,22 +1467,29 @@
if (!useActiveColoring && !mChangeVolumeRowTintWhenInactive) {
return;
}
- final ColorStateList tint = useActiveColoring
+ final ColorStateList colorTint = useActiveColoring
? Utils.getColorAccent(mContext)
: Utils.getColorAttr(mContext, android.R.attr.colorForeground);
final int alpha = useActiveColoring
- ? Color.alpha(tint.getDefaultColor())
+ ? Color.alpha(colorTint.getDefaultColor())
: getAlphaAttr(android.R.attr.secondaryContentAlpha);
- if (tint == row.cachedTint) return;
- row.slider.setProgressTintList(tint);
- row.slider.setThumbTintList(tint);
- row.slider.setProgressBackgroundTintList(tint);
- row.slider.setAlpha(((float) alpha) / 255);
- row.icon.setImageTintList(tint);
- row.icon.setImageAlpha(alpha);
- row.cachedTint = tint;
+
+ final ColorStateList bgTint = Utils.getColorAttr(
+ mContext, android.R.attr.colorBackgroundFloating);
+
+ row.sliderProgressSolid.setTintList(colorTint);
+ row.sliderBgIcon.setTintList(colorTint);
+
+ row.sliderBgSolid.setTintList(bgTint);
+ row.sliderProgressIcon.setTintList(bgTint);
+
+ if (row.icon != null) {
+ row.icon.setImageTintList(colorTint);
+ row.icon.setImageAlpha(alpha);
+ }
+
if (row.number != null) {
- row.number.setTextColor(tint);
+ row.number.setTextColor(colorTint);
row.number.setAlpha(alpha);
}
}
@@ -1538,6 +1845,10 @@
private View view;
private TextView header;
private ImageButton icon;
+ private Drawable sliderBgSolid;
+ private AlphaTintDrawableWrapper sliderBgIcon;
+ private Drawable sliderProgressSolid;
+ private AlphaTintDrawableWrapper sliderProgressIcon;
private SeekBar slider;
private TextView number;
private int stream;
@@ -1555,5 +1866,69 @@
private int animTargetProgress;
private int lastAudibleLevel = 1;
private FrameLayout dndIcon;
+
+ void setIcon(int iconRes, Resources.Theme theme) {
+ if (icon != null) {
+ icon.setImageResource(iconRes);
+ }
+
+ sliderProgressIcon.setDrawable(view.getResources().getDrawable(iconRes, theme));
+ sliderBgIcon.setDrawable(view.getResources().getDrawable(iconRes, theme));
+ }
+ }
+
+ /**
+ * Click listener added to each ringer option in the drawer. This will initiate the animation to
+ * select and then close the ringer drawer, and actually change the ringer mode.
+ */
+ private class RingerDrawerItemClickListener implements View.OnClickListener {
+ private final int mClickedRingerMode;
+
+ RingerDrawerItemClickListener(int clickedRingerMode) {
+ mClickedRingerMode = clickedRingerMode;
+ }
+
+ @Override
+ public void onClick(View view) {
+ setRingerMode(mClickedRingerMode);
+
+ mRingerDrawerIconAnimatingSelected = getDrawerIconViewForMode(mClickedRingerMode);
+ mRingerDrawerIconAnimatingDeselected = getDrawerIconViewForMode(
+ mState.ringerModeInternal);
+
+ // Begin switching the selected icon and deselected icon colors since the background is
+ // going to animate behind the new selection.
+ mRingerDrawerIconColorAnimator.start();
+
+ mSelectedRingerContainer.setVisibility(View.INVISIBLE);
+ mRingerDrawerNewSelectionBg.setAlpha(1f);
+ mRingerDrawerNewSelectionBg.animate()
+ .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
+ .setDuration(DRAWER_ANIMATION_DURATION_SHORT)
+ .withEndAction(() -> {
+ mRingerDrawerNewSelectionBg.setAlpha(0f);
+
+ if (!isLandscape()) {
+ mSelectedRingerContainer.setTranslationY(
+ getTranslationInDrawerForRingerMode(mClickedRingerMode));
+ } else {
+ mSelectedRingerContainer.setTranslationX(
+ getTranslationInDrawerForRingerMode(mClickedRingerMode));
+ }
+
+ mSelectedRingerContainer.setVisibility(VISIBLE);
+ hideRingerDrawer();
+ });
+
+ if (!isLandscape()) {
+ mRingerDrawerNewSelectionBg.animate()
+ .translationY(getTranslationInDrawerForRingerMode(mClickedRingerMode))
+ .start();
+ } else {
+ mRingerDrawerNewSelectionBg.animate()
+ .translationX(getTranslationInDrawerForRingerMode(mClickedRingerMode))
+ .start();
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 4611fe03..8d3a040 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -77,6 +77,8 @@
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.startingsurface.StartingSurface;
+import com.android.wm.shell.startingsurface.StartingWindowController;
import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -448,6 +450,22 @@
@BindsOptionalOf
abstract AppPairsController optionalAppPairs();
+ // Starting window
+
+ @WMSingleton
+ @Provides
+ static Optional<StartingSurface> provideStartingSurface(
+ StartingWindowController startingWindowController) {
+ return Optional.of(startingWindowController.asStartingSurface());
+ }
+
+ @WMSingleton
+ @Provides
+ static StartingWindowController provideStartingWindowController(Context context,
+ @ShellMainThread ShellExecutor mainExecutor) {
+ return new StartingWindowController(context, mainExecutor);
+ }
+
//
// Task view factory
//
@@ -479,6 +497,7 @@
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
+ Optional<StartingSurface> startingSurface,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
@ShellMainThread ShellExecutor mainExecutor) {
@@ -488,6 +507,7 @@
legacySplitScreenOptional,
splitScreenOptional,
appPairsOptional,
+ startingSurface,
fullscreenTaskListener,
transitions,
mainExecutor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 97cb873..2526990 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -16,8 +16,8 @@
package com.android.systemui.appops;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static junit.framework.TestCase.assertFalse;
@@ -125,9 +125,9 @@
when(mAudioManager.getActiveRecordingConfigurations())
.thenReturn(List.of(mPausedMockRecording));
- when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ when(mSensorPrivacyController.isSensorBlocked(CAMERA))
.thenReturn(false);
- when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+ when(mSensorPrivacyController.isSensorBlocked(CAMERA))
.thenReturn(false);
mController = new AppOpsControllerImpl(
@@ -505,7 +505,7 @@
assertFalse(list.get(0).isDisabled());
// Add a camera op, and disable the microphone. The camera op should be the only op returned
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, true);
+ mController.onSensorBlockedChanged(MICROPHONE, true);
mController.onOpActiveChanged(
AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
mTestableLooper.processAllMessages();
@@ -515,7 +515,7 @@
// Re enable the microphone, and verify the op returns
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, false);
+ mController.onSensorBlockedChanged(MICROPHONE, false);
mTestableLooper.processAllMessages();
list = mController.getActiveAppOps();
@@ -538,7 +538,7 @@
assertFalse(list.get(0).isDisabled());
// Add an audio op, and disable the camera. The audio op should be the only op returned
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, true);
+ mController.onSensorBlockedChanged(CAMERA, true);
mController.onOpActiveChanged(
AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
mTestableLooper.processAllMessages();
@@ -547,7 +547,7 @@
assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
// Re enable the camera, and verify the op returns
- mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, false);
+ mController.onSensorBlockedChanged(CAMERA, false);
mTestableLooper.processAllMessages();
list = mController.getActiveAppOps();
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 3e873d1..700f101 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -150,7 +150,10 @@
}
@Test
- public void dozeTimeTick() {
+ public void dozeTimeTick() throws RemoteException {
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+ mFgExecutor.runAllReady();
mUdfpsController.dozeTimeTick();
verify(mUdfpsView).dozeTimeTick();
}
@@ -240,7 +243,8 @@
@Test
public void registersViewForCallbacks() throws RemoteException {
- verify(mStatusBarStateController).addCallback(mUdfpsView);
- verify(mStatusBar).addExpansionChangedListener(mUdfpsView);
+ verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener);
+ verify(mStatusBar).addExpansionChangedListener(
+ mUdfpsController.mStatusBarExpansionListener);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
index 5c179d4..c8f223b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
@@ -69,7 +69,7 @@
mNearestTouchFrame.addView(left);
mNearestTouchFrame.addView(right);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0,
12 /* x */, 5 /* y */, 0);
@@ -86,7 +86,7 @@
mNearestTouchFrame.addView(left);
mNearestTouchFrame.addView(right);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0,
12 /* x */, 5 /* y */, 0);
@@ -105,7 +105,7 @@
mNearestTouchFrame.addView(left);
mNearestTouchFrame.addView(right);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
// Would go to left view if attached, but goes to right instead as left should be detached.
MotionEvent ev = MotionEvent.obtain(0, 0, 0,
@@ -122,7 +122,7 @@
mNearestTouchFrame.addView(left);
mNearestTouchFrame.addView(right);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0,
12 /* x */, 5 /* y */, 0);
@@ -138,7 +138,7 @@
mNearestTouchFrame.addView(left);
mNearestTouchFrame.addView(right);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0,
18 /* x */, 5 /* y */, 0);
@@ -154,7 +154,7 @@
mNearestTouchFrame.setIsVertical(true);
mNearestTouchFrame.addView(top);
mNearestTouchFrame.addView(bottom);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0,
5 /* x */, 12 /* y */, 0);
@@ -170,7 +170,7 @@
mNearestTouchFrame.setIsVertical(true);
mNearestTouchFrame.addView(top);
mNearestTouchFrame.addView(bottom);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0,
5 /* x */, 18 /* y */, 0);
@@ -184,7 +184,7 @@
View view = mockViewAt(0, 20, 10, 10);
when(view.isAttachedToWindow()).thenReturn(false);
mNearestTouchFrame.addView(view);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0, 5 /* x */, 18 /* y */, 0);
mNearestTouchFrame.onTouchEvent(ev);
@@ -201,7 +201,7 @@
mNearestTouchFrame.addView(view1);
mNearestTouchFrame.addView(view2);
mNearestTouchFrame.addView(view3);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 30, 30);
MotionEvent ev = MotionEvent.obtain(0, 0, 0, 5 /* x */, 18 /* y */, 0);
mNearestTouchFrame.onTouchEvent(ev);
@@ -213,11 +213,9 @@
public void testCachedRegionsSplit_horizontal() {
View left = mockViewAt(0, 0, 5, 20);
View right = mockViewAt(15, 0, 5, 20);
- mNearestTouchFrame.layout(0, 0, 20, 20);
-
mNearestTouchFrame.addView(left);
mNearestTouchFrame.addView(right);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.layout(0, 0, 20, 20);
Map<View, Rect> childRegions = mNearestTouchFrame.getFullTouchableChildRegions();
assertEquals(2, childRegions.size());
@@ -231,12 +229,10 @@
public void testCachedRegionsSplit_vertical() {
View top = mockViewAt(0, 0, 20, 5);
View bottom = mockViewAt(0, 15, 20, 5);
- mNearestTouchFrame.layout(0, 0, 20, 20);
- mNearestTouchFrame.setIsVertical(true);
-
mNearestTouchFrame.addView(top);
mNearestTouchFrame.addView(bottom);
- mNearestTouchFrame.onMeasure(0, 0);
+ mNearestTouchFrame.setIsVertical(true);
+ mNearestTouchFrame.layout(0, 0, 20, 20);
Map<View, Rect> childRegions = mNearestTouchFrame.getFullTouchableChildRegions();
assertEquals(2, childRegions.size());
@@ -256,6 +252,8 @@
}).when(v).getLocationInWindow(any());
when(v.isClickable()).thenReturn(true);
when(v.isAttachedToWindow()).thenReturn(true);
+ when(v.getWidth()).thenReturn(width);
+ when(v.getHeight()).thenReturn(height);
// Stupid final methods.
v.setLeft(0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index c8e9396..2a4b41c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -464,7 +464,7 @@
new PeopleSpaceTile
.Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
.setPackageName(PACKAGE_NAME)
- .setUid(0)
+ .setUserHandle(new UserHandle(0))
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
.augmentTileFromNotification(mContext, tile, sbn);
@@ -482,7 +482,7 @@
new PeopleSpaceTile
.Builder(SHORTCUT_ID_3, "userName", ICON, new Intent())
.setPackageName(PACKAGE_NAME)
- .setUid(0)
+ .setUserHandle(new UserHandle(0))
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
.augmentTileFromNotification(mContext, tile, sbn);
@@ -496,7 +496,7 @@
new PeopleSpaceTile
.Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
.setPackageName(PACKAGE_NAME)
- .setUid(0)
+ .setUserHandle(new UserHandle(0))
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
.augmentTileFromVisibleNotifications(mContext, tile,
@@ -511,7 +511,7 @@
new PeopleSpaceTile
.Builder(SHORTCUT_ID_4, "userName", ICON, new Intent())
.setPackageName(PACKAGE_NAME)
- .setUid(0)
+ .setUserHandle(new UserHandle(0))
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
.augmentTileFromVisibleNotifications(mContext, tile,
@@ -526,7 +526,7 @@
new PeopleSpaceTile
.Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
.setPackageName(PACKAGE_NAME)
- .setUid(0)
+ .setUserHandle(new UserHandle(0))
.build();
List<PeopleSpaceTile> actualList = PeopleSpaceUtils
.augmentTilesFromVisibleNotifications(
@@ -545,13 +545,13 @@
new PeopleSpaceTile
.Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
.setPackageName(PACKAGE_NAME)
- .setUid(1)
+ .setUserHandle(new UserHandle(0))
.build();
PeopleSpaceTile tile2 =
new PeopleSpaceTile
.Builder(SHORTCUT_ID_2, "userName2", ICON, new Intent())
.setPackageName(PACKAGE_NAME)
- .setUid(0)
+ .setUserHandle(new UserHandle(0))
.build();
List<PeopleSpaceTile> actualList = PeopleSpaceUtils
.augmentTilesFromVisibleNotifications(mContext, List.of(tile1, tile2),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 1c8324c..800d859 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -109,7 +109,7 @@
new PeopleSpaceTile
.Builder(SHORTCUT_ID, "username", ICON, new Intent())
.setPackageName(TEST_PACKAGE_A)
- .setUid(0)
+ .setUserHandle(new UserHandle(1))
.setNotificationKey(NOTIFICATION_KEY + "1")
.setNotificationContent(NOTIFICATION_CONTENT)
.setNotificationDataUri(URI)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 2dfd388..d40e6a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -89,6 +89,8 @@
private View mEdit;
@Mock
private MultiUserSwitch mMultiUserSwitch;
+ @Mock
+ private View mPowerMenuLiteView;
private QSFooterViewController mController;
@@ -111,11 +113,12 @@
when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
when(mView.findViewById(android.R.id.edit)).thenReturn(mEdit);
when(mView.findViewById(R.id.multi_user_switch)).thenReturn(mMultiUserSwitch);
+ when(mView.findViewById(R.id.pm_lite)).thenReturn(mPowerMenuLiteView);
mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
new QSDetailDisplayer(), mQuickQSPanelController, mFakeTunerService,
- mMetricsLogger);
+ mMetricsLogger, false);
mController.init();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index 0dfebab..a2a179e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -121,7 +121,6 @@
mQSTileHost, mQSCustomizerController, true, mMediaHost,
mQSTileRevealControllerFactory, mDumpManager, mMetricsLogger, mUiEventLogger,
mQSLogger, mBrightnessControllerFactory, mToggleSliderViewControllerFactory,
- /* labelsFlag */ false,
mFeatureFlags
);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 5870200..cb380d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -87,7 +87,6 @@
uiEventLogger,
qsLogger,
dumpManager,
- false,
featureFlags
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 1ec1da4..5a1bd5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -36,6 +36,7 @@
import com.android.keyguard.CarrierTextController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import com.android.systemui.utils.os.FakeHandler;
@@ -215,10 +216,11 @@
@Test // throws no Exception
public void testSetMobileDataIndicators_invalidSim() {
- mSignalCallback.setMobileDataIndicators(
+ MobileDataIndicators indicators = new MobileDataIndicators(
mock(NetworkController.IconState.class),
mock(NetworkController.IconState.class),
0, 0, true, true, "", "", "", true, 0, true, true);
+ mSignalCallback.setMobileDataIndicators(indicators);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index faf43a2..1c29a81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -46,6 +46,7 @@
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import org.junit.Before;
import org.junit.Test;
@@ -134,9 +135,11 @@
public void testStateUnavailable_wifiDisabled() {
NetworkController.IconState qsIcon =
new NetworkController.IconState(false, 0, "");
- mSignalCallback.setWifiIndicators(false, mock(NetworkController.IconState.class),
+ WifiIndicators indicators = new WifiIndicators(
+ false, mock(NetworkController.IconState.class),
qsIcon, false,false, "",
false, "");
+ mSignalCallback.setWifiIndicators(indicators);
mTestableLooper.processAllMessages();
assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
@@ -146,9 +149,11 @@
public void testStateUnavailable_wifiNotConnected() {
NetworkController.IconState qsIcon =
new NetworkController.IconState(false, 0, "");
- mSignalCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ WifiIndicators indicators = new WifiIndicators(
+ true, mock(NetworkController.IconState.class),
qsIcon, false,false, "",
false, "");
+ mSignalCallback.setWifiIndicators(indicators);
mTestableLooper.processAllMessages();
assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
@@ -157,9 +162,11 @@
private void enableWifiAndProcessMessages() {
NetworkController.IconState qsIcon =
new NetworkController.IconState(true, 0, "");
- mSignalCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ WifiIndicators indicators = new WifiIndicators(
+ true, mock(NetworkController.IconState.class),
qsIcon, false,false, "",
false, "");
+ mSignalCallback.setWifiIndicators(indicators);
mTestableLooper.processAllMessages();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
index a75c39c..9e62a62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
@@ -24,6 +24,7 @@
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
+import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.view.IScrollCaptureCallbacks;
import android.view.IScrollCaptureConnection;
@@ -46,7 +47,7 @@
}
@Override
- public void startCapture(Surface surface) {
+ public ICancellationSignal startCapture(Surface surface) {
mSurface = surface;
mHwuiContext = new HwuiContext(false, surface);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -56,27 +57,28 @@
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
+ return null;
}
@Override
- public void requestImage(Rect rect) {
+ public ICancellationSignal requestImage(Rect rect) {
Canvas canvas = mHwuiContext.lockCanvas(rect.width(), rect.height());
mPaint.setColor(mColors[mNextColor]);
canvas.drawRect(rect, mPaint);
mNextColor = (mNextColor++) % mColors.length;
- long frameNumber = mSurface.getNextFrameNumber();
mHwuiContext.unlockAndPost(canvas);
try {
- mCallbacks.onCaptureBufferSent(frameNumber, rect);
+ mCallbacks.onImageRequestCompleted(0, rect);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
+ return null;
}
@Override
- public void endCapture() {
+ public ICancellationSignal endCapture() {
try {
- mCallbacks.onConnectionClosed();
+ mCallbacks.onCaptureEnded();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
} finally {
@@ -84,6 +86,12 @@
mSurface = null;
mCallbacks = null;
}
+ return null;
+ }
+
+ @Override
+ public void close() throws RemoteException {
+
}
// From android.view.Surface, but issues render requests synchronously with waitForPresent(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
index 580f800..802b462 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -29,7 +29,6 @@
import static java.util.Objects.requireNonNull;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.RemoteException;
@@ -37,6 +36,7 @@
import android.view.Display;
import android.view.IScrollCaptureCallbacks;
import android.view.IWindowManager;
+import android.view.ScrollCaptureResponse;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -82,10 +82,11 @@
public void testBasicClientFlow() throws RemoteException {
doAnswer((Answer<Void>) invocation -> {
IScrollCaptureCallbacks cb = invocation.getArgument(3);
- cb.onConnected(
- new FakeScrollCaptureConnection(cb),
- /* scrollBounds */ new Rect(0, 0, 100, 100),
- /* positionInWindow */ new Point(0, 0));
+ cb.onScrollCaptureResponse(new ScrollCaptureResponse.Builder()
+ .setBoundsInWindow(new Rect(0, 0, 100, 100))
+ .setWindowBounds(new Rect(0, 0, 100, 100))
+ .setConnection(new FakeScrollCaptureConnection(cb))
+ .build());
return null;
}).when(mWm).requestScrollCapture(/* displayId */ anyInt(), /* token */ isNull(),
/* taskId */ anyInt(), any(IScrollCaptureCallbacks.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
index 2b3ca7c..6564d58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
@@ -19,15 +19,14 @@
import static org.junit.Assert.fail;
import android.content.Intent;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.util.Log;
import android.view.Display;
import android.view.IScrollCaptureCallbacks;
-import android.view.IScrollCaptureConnection;
import android.view.IWindowManager;
+import android.view.ScrollCaptureResponse;
import android.view.WindowManagerGlobal;
import androidx.test.filters.SmallTest;
@@ -67,31 +66,27 @@
wms.requestScrollCapture(Display.DEFAULT_DISPLAY, null, -1,
new IScrollCaptureCallbacks.Stub() {
@Override
- public void onConnected(
- IScrollCaptureConnection connection, Rect scrollBounds,
- Point positionInWindow) {
- Log.d(TAG,
- "client connected: " + connection + "[scrollBounds= "
- + scrollBounds + ", "
- + "positionInWindow=" + positionInWindow + "]");
+ public void onScrollCaptureResponse(ScrollCaptureResponse response)
+ throws RemoteException {
+ Log.d(TAG, "onScrollCaptureResponse: " + response);
latch.countDown();
}
@Override
- public void onUnavailable() {
- }
-
- @Override
public void onCaptureStarted() {
}
@Override
- public void onCaptureBufferSent(long frameNumber, Rect capturedArea) {
+ public void onImageRequestCompleted(int i, Rect rect)
+ throws RemoteException {
+
}
@Override
- public void onConnectionClosed() {
+ public void onCaptureEnded() throws RemoteException {
+
}
+
});
} catch (RemoteException e) {
Log.e(TAG, "request failed", e);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index ce14bca..7ff056e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
@@ -40,6 +42,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
@@ -94,8 +97,12 @@
private static final String ORGANIZATION_NAME = "organization";
+ private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
+ "bar");
+
private String mDisclosureWithOrganization;
private String mDisclosureGeneric;
+ private String mFinancedDisclosureWithOrganization;
@Mock
private DevicePolicyManager mDevicePolicyManager;
@@ -156,6 +163,8 @@
mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
ORGANIZATION_NAME);
mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
+ mFinancedDisclosureWithOrganization = mContext.getString(
+ R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
@@ -165,6 +174,11 @@
.thenReturn(mIndicationAreaBottom);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
+ when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+ .thenReturn(DEVICE_OWNER_COMPONENT);
+ when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+ .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
+
mWakeLock = new WakeLockFake();
mWakeLockBuilder = new WakeLockFake.Builder(mContext);
mWakeLockBuilder.setWakeLock(mWakeLock);
@@ -372,6 +386,22 @@
}
@Test
+ public void disclosure_deviceOwner_financedDeviceWithOrganizationName() {
+ createController();
+
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+ when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+ when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+ .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
+ sendUpdateDisclosureBroadcast();
+
+ verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ mKeyguardIndicationCaptor.capture(), eq(false));
+ assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+ .isEqualTo(mFinancedDisclosureWithOrganization);
+ }
+
+ @Test
public void transientIndication_holdsWakeLock_whenDozing() {
createController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 67c1a08..2418243 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -30,7 +30,9 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -86,28 +88,24 @@
boolean out = true;
String description = "Test";
String secondaryLabel = "Secondary label";
- mHandler.setWifiIndicators(enabled, status, qs, in, out, description, true, secondaryLabel);
+ WifiIndicators indicators = new WifiIndicators(
+ enabled, status, qs, in, out, description, true, secondaryLabel);
+ mHandler.setWifiIndicators(indicators);
waitForCallbacks();
- ArgumentCaptor<Boolean> enableArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
- ArgumentCaptor<Boolean> isTransient = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<String> secondary = ArgumentCaptor.forClass(String.class);
- Mockito.verify(mSignalCallback).setWifiIndicators(enableArg.capture(),
- statusArg.capture(), qsArg.capture(), inArg.capture(), outArg.capture(),
- descArg.capture(), isTransient.capture(), secondary.capture());
- assertEquals(enabled, (boolean) enableArg.getValue());
- assertEquals(status, statusArg.getValue());
- assertEquals(qs, qsArg.getValue());
- assertEquals(in, (boolean) inArg.getValue());
- assertEquals(out, (boolean) outArg.getValue());
- assertEquals(description, descArg.getValue());
- assertTrue(isTransient.getValue());
- assertEquals(secondaryLabel, secondary.getValue());
+ ArgumentCaptor<WifiIndicators> indicatorArg =
+ ArgumentCaptor.forClass(WifiIndicators.class);
+ Mockito.verify(mSignalCallback).setWifiIndicators(indicatorArg.capture());
+ WifiIndicators expected = indicatorArg.getValue();
+
+ assertEquals(enabled, expected.enabled);
+ assertEquals(status, expected.statusIcon);
+ assertEquals(qs, expected.qsIcon);
+ assertEquals(in, expected.activityIn);
+ assertEquals(out, expected.activityOut);
+ assertEquals(description, expected.description);
+ assertTrue(expected.isTransient);
+ assertEquals(secondaryLabel, expected.statusLabel);
}
@Test
@@ -124,37 +122,30 @@
boolean wide = true;
int subId = 5;
boolean roaming = true;
- mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, typeDescription,
+ MobileDataIndicators indicators = new MobileDataIndicators(
+ status, qs, type, qsType, in, out, typeDescription,
typeDescriptionHtml, description, wide, subId, roaming, true);
+ mHandler.setMobileDataIndicators(indicators);
waitForCallbacks();
- ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<CharSequence> typeContentArg = ArgumentCaptor.forClass(CharSequence.class);
- ArgumentCaptor<CharSequence> typeContentHtmlArg =
- ArgumentCaptor.forClass(CharSequence.class);
- ArgumentCaptor<CharSequence> descArg = ArgumentCaptor.forClass(CharSequence.class);
- ArgumentCaptor<Boolean> wideArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class);
- Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(),
- qsArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), inArg.capture(),
- outArg.capture(), typeContentArg.capture(), typeContentHtmlArg.capture(),
- descArg.capture(), wideArg.capture(), subIdArg.capture(), eq(roaming), eq(true));
- assertEquals(status, statusArg.getValue());
- assertEquals(qs, qsArg.getValue());
- assertEquals(type, (int) typeIconArg.getValue());
- assertEquals(qsType, (int) qsTypeIconArg.getValue());
- assertEquals(in, (boolean) inArg.getValue());
- assertEquals(out, (boolean) outArg.getValue());
- assertEquals(typeDescription, typeContentArg.getValue());
- assertEquals(typeDescriptionHtml, typeContentHtmlArg.getValue());
- assertEquals(description, descArg.getValue());
- assertEquals(wide, (boolean) wideArg.getValue());
- assertEquals(subId, (int) subIdArg.getValue());
+ ArgumentCaptor<MobileDataIndicators> indicatorArg =
+ ArgumentCaptor.forClass(MobileDataIndicators.class);
+ Mockito.verify(mSignalCallback).setMobileDataIndicators(indicatorArg.capture());
+ MobileDataIndicators expected = indicatorArg.getValue();
+
+ assertEquals(status, expected.statusIcon);
+ assertEquals(qs, expected.qsIcon);
+ assertEquals(type, expected.statusType);
+ assertEquals(qsType, expected.qsType);
+ assertEquals(in, expected.activityIn);
+ assertEquals(out, expected.activityOut);
+ assertEquals(typeDescription, expected.typeContentDescription);
+ assertEquals(typeDescriptionHtml, expected.typeContentDescriptionHtml);
+ assertEquals(description, expected.description);
+ assertEquals(wide, expected.isWide);
+ assertEquals(subId, expected.subId);
+ assertTrue(expected.roaming);
+ assertTrue(expected.showTriangle);
}
@SuppressWarnings("unchecked")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 89cc2b5..e52b926 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -21,9 +21,9 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
+import static junit.framework.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.Matchers.isA;
@@ -76,6 +76,7 @@
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import org.junit.After;
@@ -173,8 +174,6 @@
mMockSubDefaults = mock(SubscriptionDefaults.class);
mNetCapabilities = new NetworkCapabilities();
when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
- when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn(
- new NetworkCapabilities[] { mNetCapabilities });
when(mMockTm.createForSubscriptionId(anyInt())).thenReturn(mMockTm);
doAnswer(invocation -> {
int rssi = invocation.getArgument(0);
@@ -257,8 +256,11 @@
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mMockCm, atLeastOnce())
.registerDefaultNetworkCallback(callbackArg.capture(), isA(Handler.class));
- mDefaultCallbackInWifiTracker = callbackArg.getAllValues().get(0);
- mDefaultCallbackInNetworkController = callbackArg.getAllValues().get(1);
+ int captureSize = callbackArg.getAllValues().size();
+ assertTrue(captureSize > 1);
+ assertEquals(captureSize % 2, 0);
+ mDefaultCallbackInWifiTracker = callbackArg.getAllValues().get(captureSize - 2);
+ mDefaultCallbackInNetworkController = callbackArg.getAllValues().get(captureSize - 1);
assertNotNull(mDefaultCallbackInWifiTracker);
assertNotNull(mDefaultCallbackInNetworkController);
verify(mMockCm, atLeastOnce()).registerNetworkCallback(
@@ -307,14 +309,18 @@
setLevel(DEFAULT_LEVEL);
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_UMTS);
+ setConnectivityViaCallbackInNetworkController(
+ NetworkCapabilities.TRANSPORT_CELLULAR, true, true, null);
setConnectivityViaBroadcast(
- NetworkCapabilities.TRANSPORT_CELLULAR, true, true);
+ NetworkCapabilities.TRANSPORT_CELLULAR, true, true);
}
public void setConnectivityViaBroadcastForVcn(
int networkType, boolean validated, boolean isConnected, VcnTransportInfo info) {
mNetCapabilities.setTransportInfo(info);
setConnectivityCommon(networkType, validated, isConnected);
+ mDefaultCallbackInNetworkController.onCapabilitiesChanged(
+ mock(Network.class), new NetworkCapabilities(mNetCapabilities));
Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION);
mNetworkController.onReceive(mContext, i);
}
@@ -322,6 +328,8 @@
public void setConnectivityViaBroadcast(
int networkType, boolean validated, boolean isConnected) {
setConnectivityCommon(networkType, validated, isConnected);
+ mDefaultCallbackInNetworkController.onCapabilitiesChanged(
+ mock(Network.class), new NetworkCapabilities(mNetCapabilities));
Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION);
mNetworkController.onReceive(mContext, i);
}
@@ -487,28 +495,21 @@
protected void verifyLastQsMobileDataIndicators(boolean visible, int icon, int typeIcon,
boolean dataIn, boolean dataOut) {
- ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+ ArgumentCaptor.forClass(MobileDataIndicators.class);
verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
- any(),
- iconArg.capture(),
- anyInt(),
- typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
- any(CharSequence.class), any(CharSequence.class), any(CharSequence.class),
- anyBoolean(), anyInt(), anyBoolean(), anyBoolean());
- IconState iconState = iconArg.getValue();
+ indicatorsArg.capture());
+ MobileDataIndicators expected = indicatorsArg.getValue();
int state = SignalDrawable.getState(icon, CellSignalStrength.getNumSignalStrengthLevels(),
false);
- assertEquals("Visibility in, quick settings", visible, iconState.visible);
- assertEquals("Signal icon in, quick settings", state, iconState.icon);
- assertEquals("Data icon in, quick settings", typeIcon, (int) typeIconArg.getValue());
+ assertEquals("Visibility in, quick settings", visible, expected.qsIcon.visible);
+ assertEquals("Signal icon in, quick settings", state, expected.qsIcon.icon);
+ assertEquals("Data icon in, quick settings", typeIcon, expected.qsType);
assertEquals("Data direction in, in quick settings", dataIn,
- (boolean) dataInArg.getValue());
+ expected.activityIn);
assertEquals("Data direction out, in quick settings", dataOut,
- (boolean) dataOutArg.getValue());
+ expected.activityOut);
}
protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon) {
@@ -522,44 +523,35 @@
protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
boolean roaming, boolean inet) {
- ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+ ArgumentCaptor.forClass(MobileDataIndicators.class);
// TODO: Verify all fields.
verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
- iconArg.capture(),
- any(),
- typeIconArg.capture(),
- anyInt(), anyBoolean(), anyBoolean(),
- any(CharSequence.class), any(CharSequence.class), any(),
- anyBoolean(), anyInt(), eq(roaming), anyBoolean());
- IconState iconState = iconArg.getValue();
+ indicatorsArg.capture());
+ MobileDataIndicators expected = indicatorsArg.getValue();
int state = icon == -1 ? 0
: SignalDrawable.getState(icon, CellSignalStrength.getNumSignalStrengthLevels(),
!inet);
- assertEquals("Signal icon in status bar", state, iconState.icon);
- assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
- assertEquals("Visibility in status bar", visible, iconState.visible);
+ assertEquals("Signal icon in status bar", state, expected.statusIcon.icon);
+ assertEquals("Data icon in status bar", typeIcon, expected.statusType);
+ assertEquals("Visibility in status bar", visible, expected.statusIcon.visible);
}
protected void verifyLastMobileDataIndicatorsForVcn(boolean visible, int level, int typeIcon,
boolean inet) {
- ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+ ArgumentCaptor.forClass(MobileDataIndicators.class);
verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
- iconArg.capture(),
- any(),
- typeIconArg.capture(),
- anyInt(), anyBoolean(), anyBoolean(),
- any(CharSequence.class), any(CharSequence.class), any(),
- anyBoolean(), anyInt(), anyBoolean(), anyBoolean());
- IconState iconState = iconArg.getValue();
+ indicatorsArg.capture());
+
+ MobileDataIndicators expected = indicatorsArg.getValue();
int state = SignalDrawable.getState(
level, CellSignalStrength.getNumSignalStrengthLevels(), !inet);
- assertEquals("Signal icon in status bar", state, iconState.icon);
- assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
- assertEquals("Visibility in status bar", visible, iconState.visible);
+ assertEquals("Signal icon in status bar", state, expected.statusIcon.icon);
+ assertEquals("Data icon in status bar", typeIcon, expected.statusType);
+ assertEquals("Visibility in status bar", visible, expected.statusIcon.visible);
}
protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
@@ -580,6 +572,8 @@
boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut,
boolean cutOut, CharSequence typeContentDescription,
CharSequence typeContentDescriptionHtml) {
+ ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+ ArgumentCaptor.forClass(MobileDataIndicators.class);
ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<IconState> qsIconArg = ArgumentCaptor.forClass(IconState.class);
@@ -592,17 +586,9 @@
ArgumentCaptor.forClass(CharSequence.class);
verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
- iconArg.capture(),
- qsIconArg.capture(),
- typeIconArg.capture(),
- qsTypeIconArg.capture(),
- dataInArg.capture(),
- dataOutArg.capture(),
- typeContentDescriptionArg.capture(),
- typeContentDescriptionHtmlArg.capture(),
- any(), anyBoolean(), anyInt(), anyBoolean(), anyBoolean());
+ indicatorsArg.capture());
- IconState iconState = iconArg.getValue();
+ MobileDataIndicators expected = indicatorsArg.getValue();
int numSignalStrengthBins = CellSignalStrength.getNumSignalStrengthLevels();
if (mMobileSignalController.mInflateSignalStrengths) {
@@ -610,29 +596,28 @@
icon++;
}
int state = SignalDrawable.getState(icon, numSignalStrengthBins, cutOut);
- assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
- assertEquals("Signal icon in status bar", state, iconState.icon);
- assertEquals("Visibility in status bar", visible, iconState.visible);
+ assertEquals("Data icon in status bar", typeIcon, expected.statusType);
+ assertEquals("Signal icon in status bar", state, expected.statusIcon.icon);
+ assertEquals("Visibility in status bar", visible, expected.statusIcon.visible);
- iconState = qsIconArg.getValue();
if (visible) {
- assertEquals("Visibility in quick settings", qsVisible, iconState.visible);
- assertEquals("Signal icon in quick settings", state, iconState.icon);
+ assertEquals("Visibility in quick settings", qsVisible, expected.qsIcon.visible);
+ assertEquals("Signal icon in quick settings", state, expected.qsIcon.icon);
} else {
- assertEquals("Cellular is not default", null, iconState);
+ assertEquals("Cellular is not default", null, expected.qsIcon);
}
- assertEquals("Data icon in quick settings", qsTypeIcon, (int) qsTypeIconArg.getValue());
+ assertEquals("Data icon in quick settings", qsTypeIcon, expected.qsType);
assertEquals("Data direction in in quick settings", dataIn,
- (boolean) dataInArg.getValue());
+ expected.activityIn);
assertEquals("Data direction out in quick settings", dataOut,
- (boolean) dataOutArg.getValue());
+ expected.activityOut);
if (typeContentDescription != null) { // Only check if it was provided
assertEquals("Type content description", typeContentDescription,
- typeContentDescriptionArg.getValue());
+ expected.typeContentDescription);
}
if (typeContentDescriptionHtml != null) { // Only check if it was provided
assertEquals("Type content description (html)", typeContentDescriptionHtml,
- typeContentDescriptionHtmlArg.getValue());
+ expected.typeContentDescriptionHtml);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index fc1a08ac..c6812a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -3,7 +3,6 @@
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -21,7 +20,7 @@
import android.testing.TestableLooper.RunWithLooper;
import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
import org.junit.Before;
import org.junit.Test;
@@ -316,44 +315,42 @@
}
protected void verifyLastQsDataDirection(boolean in, boolean out) {
- ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<WifiIndicators> indicatorsArg =
+ ArgumentCaptor.forClass(WifiIndicators.class);
Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
- anyBoolean(), any(), any(), inArg.capture(), outArg.capture(), any(), anyBoolean(),
- any());
- assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue());
- assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue());
+ indicatorsArg.capture());
+ WifiIndicators expected = indicatorsArg.getValue();
+ assertEquals("WiFi data in, in quick settings", in, expected.activityIn);
+ assertEquals("WiFi data out, in quick settings", out, expected.activityOut);
}
protected void verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon,
String description) {
- ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
- ArgumentCaptor<Boolean> enabledArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
+ ArgumentCaptor<WifiIndicators> indicatorsArg =
+ ArgumentCaptor.forClass(WifiIndicators.class);
Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
- enabledArg.capture(), any(), iconArg.capture(), anyBoolean(),
- anyBoolean(), descArg.capture(), anyBoolean(), any());
- IconState iconState = iconArg.getValue();
- assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
- assertEquals("WiFI desc (ssid), in quick settings", description, descArg.getValue());
+ indicatorsArg.capture());
+ WifiIndicators expected = indicatorsArg.getValue();
+ assertEquals("WiFi enabled, in quick settings", enabled, expected.enabled);
+ assertEquals("WiFI desc (ssid), in quick settings", description, expected.description);
if (enabled && connected) {
- assertEquals("WiFi connected, in quick settings", connected, iconState.visible);
- assertEquals("WiFi signal, in quick settings", icon, iconState.icon);
+ assertEquals("WiFi connected, in quick settings", connected, expected.qsIcon.visible);
+ assertEquals("WiFi signal, in quick settings", icon, expected.qsIcon.icon);
} else {
- assertEquals("WiFi is not default", null, iconState);
+ assertEquals("WiFi is not default", null, expected.qsIcon);
}
}
protected void verifyLastWifiIcon(boolean visible, int icon) {
- ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
+ ArgumentCaptor<WifiIndicators> indicatorsArg =
+ ArgumentCaptor.forClass(WifiIndicators.class);
Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
- anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(),
- any(), anyBoolean(), any());
- IconState iconState = iconArg.getValue();
- assertEquals("WiFi visible, in status bar", visible, iconState.visible);
- assertEquals("WiFi signal, in status bar", icon, iconState.icon);
+ indicatorsArg.capture());
+ WifiIndicators expected = indicatorsArg.getValue();
+ assertEquals("WiFi visible, in status bar", visible, expected.statusIcon.visible);
+ assertEquals("WiFi signal, in status bar", icon, expected.statusIcon.icon);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index e798207..6067b42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -32,7 +32,6 @@
import static com.android.systemui.theme.ThemeOverlayApplier.THEME_CATEGORIES;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -88,7 +87,9 @@
private static final String THEMEPICKER_PACKAGE = "com.android.wallpaper";
private static final String LAUNCHER_PACKAGE = "com.android.launcher3";
private static final UserHandle TEST_USER = UserHandle.of(5);
- private static final Set<UserHandle> TEST_USER_HANDLES = Sets.newHashSet(TEST_USER);
+ private static final UserHandle TEST_USER_MANAGED_PROFILE = UserHandle.of(6);
+ private static final Set<UserHandle> TEST_USER_HANDLES =
+ Sets.newHashSet(TEST_USER_MANAGED_PROFILE);
@Mock
OverlayManager mOverlayManager;
@@ -159,13 +160,19 @@
THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, false),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_THEME_PICKER,
THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, true)));
+
+ OverlayInfo launcherTargetInfo = new OverlayInfo("packageName", LAUNCHER_PACKAGE,
+ null, null, "/", 0, 0, 0, false);
+ when(mOverlayManager.getOverlayInfo(any(OverlayIdentifier.class), any()))
+ .thenReturn(launcherTargetInfo);
clearInvocations(mOverlayManager);
verify(mDumpManager).registerDumpable(any(), any());
}
@Test
public void allCategoriesSpecified_allEnabledExclusively() {
- mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
+ mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
+ TEST_USER_HANDLES);
verify(mOverlayManager).commit(any());
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
@@ -176,7 +183,8 @@
@Test
public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
- mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
+ mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
+ TEST_USER_HANDLES);
for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) {
if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
@@ -192,27 +200,25 @@
@Test
public void allCategoriesSpecified_enabledForAllUserHandles() {
Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
- UserHandle newUserHandle = UserHandle.of(10);
- userHandles.add(newUserHandle);
- mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, userHandles);
+ mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
+ userHandles);
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
eq(TEST_USER.getIdentifier()));
- verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
- eq(newUserHandle.getIdentifier()));
+ // Not enabled for work profile because the target package is LAUNCHER_PACKAGE
+ verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true),
+ eq(TEST_USER_MANAGED_PROFILE.getIdentifier()));
}
}
@Test
public void applyCurrentUserOverlays_createsPendingOverlays() {
- Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
- UserHandle newUserHandle = UserHandle.of(10);
- userHandles.add(newUserHandle);
- FabricatedOverlay[] pendingCreation = new FabricatedOverlay[] {
+ FabricatedOverlay[] pendingCreation = new FabricatedOverlay[]{
mock(FabricatedOverlay.class)
};
- mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation, userHandles);
+ mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation,
+ TEST_USER.getIdentifier(), TEST_USER_HANDLES);
for (FabricatedOverlay overlay : pendingCreation) {
verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay));
@@ -220,20 +226,13 @@
}
@Test
- public void allCategoriesSpecified_overlayManagerNotQueried() {
- mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
-
- verify(mOverlayManager, never())
- .getOverlayInfosForTarget(anyString(), any(UserHandle.class));
- }
-
- @Test
public void someCategoriesSpecified_specifiedEnabled_unspecifiedDisabled() {
Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID);
- mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
+ mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
+ TEST_USER_HANDLES);
for (OverlayIdentifier overlayPackage : categoryToPackage.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
@@ -249,7 +248,8 @@
@Test
public void zeroCategoriesSpecified_allDisabled() {
- mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER_HANDLES);
+ mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(),
+ TEST_USER_HANDLES);
for (String category : THEME_CATEGORIES) {
verify(mTransactionBuilder).setEnabled(
@@ -263,7 +263,8 @@
Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category"));
- mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
+ mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
+ TEST_USER_HANDLES);
verify(mTransactionBuilder, never()).setEnabled(
eq(new OverlayIdentifier("com.example.blah.category")), eq(false),
@@ -273,23 +274,6 @@
eq(TEST_USER.getIdentifier()));
}
- @Test
- public void overlayManagerOnlyQueriedForUnspecifiedPackages() {
- Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
- categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
-
- mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
-
- verify(mOverlayManager).getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM);
- verify(mOverlayManager, never()).getOverlayInfosForTarget(ANDROID_PACKAGE,
- UserHandle.SYSTEM);
- verify(mOverlayManager, never()).getOverlayInfosForTarget(SYSUI_PACKAGE, UserHandle.SYSTEM);
- verify(mOverlayManager, never()).getOverlayInfosForTarget(LAUNCHER_PACKAGE,
- UserHandle.SYSTEM);
- verify(mOverlayManager, never()).getOverlayInfosForTarget(THEMEPICKER_PACKAGE,
- UserHandle.SYSTEM);
- }
-
private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName,
String category, boolean enabled) {
return new OverlayInfo(packageName, null, targetPackageName, null, category, "",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index aa385ef..d80c40f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -143,7 +143,7 @@
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -175,7 +175,7 @@
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -198,7 +198,7 @@
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index c085689..3cea175 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -22,6 +22,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.KeyguardManager;
@@ -37,6 +38,8 @@
import androidx.test.filters.SmallTest;
+import com.android.systemui.Prefs;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.VolumeDialogController.State;
@@ -58,6 +61,11 @@
public class VolumeDialogImplTest extends SysuiTestCase {
VolumeDialogImpl mDialog;
+ View mActiveRinger;
+ View mDrawerContainer;
+ View mDrawerVibrate;
+ View mDrawerMute;
+ View mDrawerNormal;
@Mock
VolumeDialogController mController;
@@ -80,6 +88,17 @@
mDialog.init(0, null);
State state = createShellState();
mDialog.onStateChangedH(state);
+
+ mActiveRinger = mDialog.getDialogView().findViewById(
+ R.id.volume_new_ringer_active_icon_container);
+ mDrawerContainer = mDialog.getDialogView().findViewById(R.id.volume_drawer_container);
+ mDrawerVibrate = mDrawerContainer.findViewById(R.id.volume_drawer_vibrate);
+ mDrawerMute = mDrawerContainer.findViewById(R.id.volume_drawer_mute);
+ mDrawerNormal = mDrawerContainer.findViewById(R.id.volume_drawer_normal);
+
+ Prefs.putInt(mContext,
+ Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT,
+ VolumePrefs.SHOW_RINGER_TOAST_COUNT + 1);
}
private State createShellState() {
@@ -207,6 +226,48 @@
verify(mController, never()).vibrate(any());
}
+ @Test
+ public void testSelectVibrateFromDrawer() {
+ final State initialUnsetState = new State();
+ initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+ mDialog.onStateChangedH(initialUnsetState);
+
+ mActiveRinger.performClick();
+ mDrawerVibrate.performClick();
+
+ // Make sure we've actually changed the ringer mode.
+ verify(mController, times(1)).setRingerMode(
+ AudioManager.RINGER_MODE_VIBRATE, false);
+ }
+
+ @Test
+ public void testSelectMuteFromDrawer() {
+ final State initialUnsetState = new State();
+ initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+ mDialog.onStateChangedH(initialUnsetState);
+
+ mActiveRinger.performClick();
+ mDrawerMute.performClick();
+
+ // Make sure we've actually changed the ringer mode.
+ verify(mController, times(1)).setRingerMode(
+ AudioManager.RINGER_MODE_SILENT, false);
+ }
+
+ @Test
+ public void testSelectNormalFromDrawer() {
+ final State initialUnsetState = new State();
+ initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE;
+ mDialog.onStateChangedH(initialUnsetState);
+
+ mActiveRinger.performClick();
+ mDrawerNormal.performClick();
+
+ // Make sure we've actually changed the ringer mode.
+ verify(mController, times(1)).setRingerMode(
+ AudioManager.RINGER_MODE_NORMAL, false);
+ }
+
/*
@Test
public void testContentDescriptions() {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
index feed18d..3d8f5173 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
@@ -98,8 +98,7 @@
}
mProcessMotionEvent = true;
for (int i = 0; i < mGestureMatchers.size(); i++) {
- final GestureMatcher matcher =
- mGestureMatchers.get(i);
+ final GestureMatcher matcher = mGestureMatchers.get(i);
matcher.onMotionEvent(event, rawEvent, policyFlags);
if (matcher.getState() == GestureMatcher.STATE_GESTURE_COMPLETED) {
clear();
@@ -128,7 +127,10 @@
MotionEvent rawEvent, int policyFlags) {
if (state == GestureMatcher.STATE_GESTURE_COMPLETED) {
mListener.onGestureCompleted(gestureId, event, rawEvent, policyFlags);
- //Clear the states in onMotionEvent().
+ // Ideally we clear the states in onMotionEvent(), this case is for hold gestures.
+ // If we clear before processing up event , then MultiTap matcher cancels the gesture
+ // due to incorrect state. It ends up listener#onGestureCancelled is called even
+ // the gesture is detected.
if (!mProcessMotionEvent) {
clear();
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
index 7a4d9e3..570e0ce 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
@@ -33,7 +33,7 @@
class MagnificationGestureMatcher {
private static final int GESTURE_BASE = 100;
- public static final int GESTURE_TWO_FINGER_DOWN = GESTURE_BASE + 1;
+ public static final int GESTURE_TWO_FINGERS_DOWN_OR_SWIPE = GESTURE_BASE + 1;
public static final int GESTURE_SWIPE = GESTURE_BASE + 2;
public static final int GESTURE_SINGLE_TAP = GESTURE_BASE + 3;
public static final int GESTURE_SINGLE_TAP_AND_HOLD = GESTURE_BASE + 4;
@@ -41,7 +41,7 @@
public static final int GESTURE_TRIPLE_TAP_AND_HOLD = GESTURE_BASE + 6;
@IntDef(prefix = {"GESTURE_MAGNIFICATION_"}, value = {
- GESTURE_TWO_FINGER_DOWN,
+ GESTURE_TWO_FINGERS_DOWN_OR_SWIPE,
GESTURE_SWIPE
})
@Retention(RetentionPolicy.SOURCE)
@@ -57,8 +57,8 @@
switch (gestureId) {
case GESTURE_SWIPE:
return "GESTURE_SWIPE";
- case GESTURE_TWO_FINGER_DOWN:
- return "GESTURE_TWO_FINGER_DOWN";
+ case GESTURE_TWO_FINGERS_DOWN_OR_SWIPE:
+ return "GESTURE_TWO_FINGERS_DOWN_OR_SWIPE";
case GESTURE_SINGLE_TAP:
return "GESTURE_SINGLE_TAP";
case GESTURE_SINGLE_TAP_AND_HOLD:
@@ -71,6 +71,12 @@
return "none";
}
+ /**
+ * @param context
+ * @return the duration in milliseconds between the first tap's down event and
+ * the second tap's down event to be considered that the user is going to performing
+ * panning/scaling gesture.
+ */
static int getMagnificationMultiTapTimeout(Context context) {
return ViewConfiguration.getDoubleTapTimeout() + context.getResources().getInteger(
R.integer.config_screen_magnification_multi_tap_adjustment);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index a209086..085c343 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -65,7 +65,7 @@
* the last event before timeout.
*
* @see MagnificationGestureMatcher#GESTURE_SWIPE
- * @see MagnificationGestureMatcher#GESTURE_TWO_FINGER_DOWN
+ * @see MagnificationGestureMatcher#GESTURE_TWO_FINGERS_DOWN_OR_SWIPE
*/
void onGestureCompleted(@GestureId int gestureId, long lastDownEventTime,
List<MotionEventInfo> delayedEventQueue, MotionEvent event);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java b/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
index cd5061f..fa15ac1 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
@@ -49,6 +49,11 @@
}
@Override
+ protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ cancelGesture(event, rawEvent, policyFlags);
+ }
+
+ @Override
protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
if (gestureMatched(event, rawEvent, policyFlags)) {
completeGesture(event, rawEvent, policyFlags);
@@ -65,7 +70,7 @@
}
private boolean gestureMatched(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- return mLastDown != null && (distance(mLastDown, event) >= mSwipeMinDistance);
+ return mLastDown != null && (distance(mLastDown, event) > mSwipeMinDistance);
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java
deleted file mode 100644
index 173a5b8..0000000
--- a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java
+++ /dev/null
@@ -1,74 +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.
- */
-
-package com.android.server.accessibility.magnification;
-
-import android.content.Context;
-import android.os.Handler;
-import android.view.MotionEvent;
-
-import com.android.server.accessibility.gestures.GestureMatcher;
-
-/**
- *
- * This class is responsible for matching two fingers down gestures. The gesture matching
- * result is determined in a duration.
- */
-final class TwoFingersDown extends GestureMatcher {
-
- private MotionEvent mLastDown;
- private final int mDetectionDurationMillis;
-
- TwoFingersDown(Context context) {
- super(MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN,
- new Handler(context.getMainLooper()), null);
- mDetectionDurationMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
- context);
- }
-
- @Override
- protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- mLastDown = MotionEvent.obtain(event);
- cancelAfter(mDetectionDurationMillis, event, rawEvent, policyFlags);
- }
-
- @Override
- protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- if (mLastDown == null) {
- cancelGesture(event, rawEvent, policyFlags);
- }
- completeGesture(event, rawEvent, policyFlags);
- }
-
- @Override
- protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- cancelGesture(event, rawEvent, policyFlags);
- }
-
- @Override
- public void clear() {
- if (mLastDown != null) {
- mLastDown.recycle();
- mLastDown = null;
- }
- super.clear();
- }
-
- @Override
- protected String getGestureName() {
- return this.getClass().getSimpleName();
- }
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java
new file mode 100644
index 0000000..1742bd4
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java
@@ -0,0 +1,123 @@
+/*
+ * 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.accessibility.magnification;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Handler;
+import android.util.MathUtils;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.server.accessibility.gestures.GestureMatcher;
+
+/**
+ * This class is responsible for detecting that the user is using two fingers to perform
+ * swiping gestures or just stay pressed on the screen. The gesture matching result is determined
+ * in a duration.
+ */
+final class TwoFingersDownOrSwipe extends GestureMatcher {
+
+ private final int mDoubleTapTimeout;
+ private final int mDetectionDurationMillis;
+ private final int mSwipeMinDistance;
+ private MotionEvent mFirstPointerDown;
+ private MotionEvent mSecondPointerDown;
+
+ TwoFingersDownOrSwipe(Context context) {
+ super(MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE,
+ new Handler(context.getMainLooper()), null);
+ mDetectionDurationMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
+ context);
+ mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+ mSwipeMinDistance = ViewConfiguration.get(context).getScaledTouchSlop();
+
+ }
+
+ @Override
+ protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ mFirstPointerDown = MotionEvent.obtain(event);
+ cancelAfter(mDetectionDurationMillis, event, rawEvent, policyFlags);
+ }
+
+ @Override
+ protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (mFirstPointerDown == null) {
+ cancelGesture(event, rawEvent, policyFlags);
+ }
+ if (event.getPointerCount() == 2) {
+ mSecondPointerDown = MotionEvent.obtain(event);
+ completeAfter(mDoubleTapTimeout, event, rawEvent, policyFlags);
+ } else {
+ cancelGesture(event, rawEvent, policyFlags);
+ }
+ }
+
+ @Override
+ protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (mFirstPointerDown == null || mSecondPointerDown == null) {
+ return;
+ }
+ if (distance(mFirstPointerDown, /* move */ event) > mSwipeMinDistance) {
+ completeGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ if (distance(mSecondPointerDown, /* move */ event) > mSwipeMinDistance) {
+ // The second pointer is swiping.
+ completeGesture(event, rawEvent, policyFlags);
+ }
+ }
+
+ @Override
+ protected void onPointerUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ cancelGesture(event, rawEvent, policyFlags);
+ }
+
+ @Override
+ protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ cancelGesture(event, rawEvent, policyFlags);
+ }
+
+ @Override
+ public void clear() {
+ if (mFirstPointerDown != null) {
+ mFirstPointerDown.recycle();
+ mFirstPointerDown = null;
+ }
+ if (mSecondPointerDown != null) {
+ mSecondPointerDown.recycle();
+ mSecondPointerDown = null;
+ }
+ super.clear();
+ }
+
+ @Override
+ protected String getGestureName() {
+ return this.getClass().getSimpleName();
+ }
+
+ private static double distance(@NonNull MotionEvent downEvent, @NonNull MotionEvent moveEvent) {
+ final int downActionIndex = downEvent.getActionIndex();
+ final int downPointerId = downEvent.getPointerId(downActionIndex);
+ final int moveActionIndex = moveEvent.findPointerIndex(downPointerId);
+ if (moveActionIndex < 0) {
+ return -1;
+ }
+ return MathUtils.dist(downEvent.getX(downActionIndex), downEvent.getY(downActionIndex),
+ moveEvent.getX(moveActionIndex), moveEvent.getY(moveActionIndex));
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 55a911e..fa34062 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -323,7 +323,7 @@
* manipulate the window magnifier or want to interact with current UI. The rule of leaving
* this state is as follows:
* <ol>
- * <li> If {@link MagnificationGestureMatcher#GESTURE_TWO_FINGER_DOWN} is detected,
+ * <li> If {@link MagnificationGestureMatcher#GESTURE_TWO_FINGERS_DOWN_OR_SWIPE} is detected,
* {@link State} will be transited to {@link PanningScalingGestureState}.</li>
* <li> If other gesture is detected and the last motion event is neither ACTION_UP nor
* ACTION_CANCEL.
@@ -357,7 +357,7 @@
new SimpleSwipe(context),
multiTap,
multiTapAndHold,
- new TwoFingersDown(context));
+ new TwoFingersDownOrSwipe(context));
}
@Override
@@ -399,7 +399,7 @@
Slog.d(mLogTag,
"onGestureDetected : delayedEventQueue = " + delayedEventQueue);
}
- if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN
+ if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE
&& mWindowMagnificationMgr.pointersInWindow(mDisplayId, motionEvent) > 0) {
transitionTo(mObservePanningScalingState);
} else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP) {
diff --git a/services/api/Android.bp b/services/api/Android.bp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/api/Android.bp
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 7518c7a..e251700 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,6 +19,7 @@
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.res.Resources.ID_NULL;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
@@ -137,7 +138,6 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -181,9 +181,6 @@
}
switch (action) {
- case Intent.ACTION_CONFIGURATION_CHANGED:
- onConfigurationChanged();
- break;
case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
synchronized (mLock) {
@@ -243,8 +240,6 @@
private Handler mSaveStateHandler;
private Handler mCallbackHandler;
- private Locale mLocale;
-
private final SparseIntArray mNextAppWidgetIds = new SparseIntArray();
private boolean mSafeMode;
@@ -290,13 +285,6 @@
}
private void registerBroadcastReceiver() {
- // Register for configuration changes so we can update the names
- // of the widgets when the locale changes.
- IntentFilter configFilter = new IntentFilter();
- configFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
- configFilter, null, null);
-
// Register for broadcasts about package install, etc., so we can
// update the provider list.
IntentFilter packageFilter = new IntentFilter();
@@ -338,62 +326,6 @@
mSafeMode = safeMode;
}
- private void onConfigurationChanged() {
- if (DEBUG) {
- Slog.i(TAG, "onConfigurationChanged()");
- }
-
- Locale revised = Locale.getDefault();
- if (revised == null || mLocale == null || !revised.equals(mLocale)) {
- mLocale = revised;
-
- synchronized (mLock) {
- SparseIntArray changedGroups = null;
-
- // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the
- // list of installed providers and skip providers that we don't need to update.
- // Also note that remove the provider does not clear the Provider component data.
- ArrayList<Provider> installedProviders = new ArrayList<>(mProviders);
- HashSet<ProviderId> removedProviders = new HashSet<>();
-
- int N = installedProviders.size();
- for (int i = N - 1; i >= 0; i--) {
- Provider provider = installedProviders.get(i);
-
- final int userId = provider.getUserId();
- if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
- isProfileWithLockedParent(userId)) {
- continue;
- }
- ensureGroupStateLoadedLocked(userId);
-
- if (!removedProviders.contains(provider.id)) {
- final boolean changed = updateProvidersForPackageLocked(
- provider.id.componentName.getPackageName(),
- provider.getUserId(), removedProviders);
-
- if (changed) {
- if (changedGroups == null) {
- changedGroups = new SparseIntArray();
- }
- final int groupId = mSecurityPolicy.getGroupParent(
- provider.getUserId());
- changedGroups.put(groupId, groupId);
- }
- }
- }
-
- if (changedGroups != null) {
- final int groupCount = changedGroups.size();
- for (int i = 0; i < groupCount; i++) {
- final int groupId = changedGroups.get(i);
- saveGroupStateAsync(groupId);
- }
- }
- }
- }
- }
-
private void onPackageBroadcastReceived(Intent intent, int userId) {
final String action = intent.getAction();
boolean added = false;
@@ -2647,9 +2579,9 @@
info.updatePeriodMillis = sa.getInt(
com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
info.initialLayout = sa.getResourceId(
- com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
+ com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, ID_NULL);
info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
- AppWidgetProviderInfo_initialKeyguardLayout, 0);
+ AppWidgetProviderInfo_initialKeyguardLayout, ID_NULL);
String className = sa
.getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
@@ -2660,11 +2592,12 @@
info.label = activityInfo.loadLabel(pm).toString();
info.icon = activityInfo.getIconResource();
info.previewImage = sa.getResourceId(
- com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
+ com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, ID_NULL);
info.previewLayout = sa.getResourceId(
- com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, 0);
+ com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, ID_NULL);
info.autoAdvanceViewId = sa.getResourceId(
- com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
+ com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId,
+ View.NO_ID);
info.resizeMode = sa.getInt(
com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
AppWidgetProviderInfo.RESIZE_NONE);
@@ -2674,8 +2607,7 @@
info.widgetFeatures = sa.getInt(
com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0);
info.descriptionRes = sa.getResourceId(
- com.android.internal.R.styleable.AppWidgetProviderInfo_description,
- Resources.ID_NULL);
+ com.android.internal.R.styleable.AppWidgetProviderInfo_description, ID_NULL);
sa.recycle();
return info;
} catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ebfa917..21cae45 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -742,6 +742,15 @@
}
}
}
+
+ if (association.isNotifyOnDeviceNearby()) {
+ ServiceConnector<ICompanionDeviceService> serviceConnector =
+ mDeviceListenerServiceConnectors.forUser(association.getUserId())
+ .get(association.getPackageName());
+ if (serviceConnector != null) {
+ serviceConnector.unbind();
+ }
+ }
}
private void updateSpecialAccessPermissionForAssociatedPackage(Association association) {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 0be485b..02930dc 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -88,7 +88,6 @@
import com.android.internal.infra.GlobalWhitelistState;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -101,6 +100,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -602,10 +602,11 @@
@Override
public void startSession(@NonNull IBinder activityToken,
- @NonNull ComponentName componentName, int sessionId, int flags,
- @NonNull IResultReceiver result) {
- Preconditions.checkNotNull(activityToken);
- Preconditions.checkNotNull(sessionId);
+ @NonNull IBinder shareableActivityToken, @NonNull ComponentName componentName,
+ int sessionId, int flags, @NonNull IResultReceiver result) {
+ Objects.requireNonNull(activityToken);
+ Objects.requireNonNull(shareableActivityToken);
+ Objects.requireNonNull(sessionId);
final int userId = UserHandle.getCallingUserId();
final ActivityPresentationInfo activityPresentationInfo = getAmInternal()
@@ -617,14 +618,14 @@
setClientState(result, STATE_DISABLED, /* binder= */ null);
return;
}
- service.startSessionLocked(activityToken, activityPresentationInfo, sessionId,
- Binder.getCallingUid(), flags, result);
+ service.startSessionLocked(activityToken, shareableActivityToken,
+ activityPresentationInfo, sessionId, Binder.getCallingUid(), flags, result);
}
}
@Override
public void finishSession(int sessionId) {
- Preconditions.checkNotNull(sessionId);
+ Objects.requireNonNull(sessionId);
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
@@ -650,7 +651,7 @@
@Override
public void removeData(@NonNull DataRemovalRequest request) {
- Preconditions.checkNotNull(request);
+ Objects.requireNonNull(request);
assertCalledByPackageOwner(request.getPackageName());
final int userId = UserHandle.getCallingUserId();
@@ -663,8 +664,8 @@
@Override
public void shareData(@NonNull DataShareRequest request,
@NonNull IDataShareWriteAdapter clientAdapter) {
- Preconditions.checkNotNull(request);
- Preconditions.checkNotNull(clientAdapter);
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(clientAdapter);
assertCalledByPackageOwner(request.getPackageName());
@@ -795,6 +796,23 @@
new ContentCaptureManagerServiceShellCommand(ContentCaptureManagerService.this).exec(
this, in, out, err, args, callback, resultReceiver);
}
+
+ @Override
+ public void resetTemporaryService(@UserIdInt int userId) {
+ ContentCaptureManagerService.this.resetTemporaryService(userId);
+ }
+
+ @Override
+ public void setTemporaryService(
+ @UserIdInt int userId, @NonNull String serviceName, int duration) {
+ ContentCaptureManagerService.this.setTemporaryService(
+ userId, serviceName, duration);
+ }
+
+ @Override
+ public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+ ContentCaptureManagerService.this.setDefaultServiceEnabled(userId, enabled);
+ }
}
private final class LocalService extends ContentCaptureManagerInternal {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index ea68e19..53cdc33 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -35,6 +35,7 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
+import android.app.assist.ActivityId;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.content.ComponentName;
@@ -241,6 +242,7 @@
@GuardedBy("mLock")
public void startSessionLocked(@NonNull IBinder activityToken,
+ @NonNull IBinder shareableActivityToken,
@NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid,
int flags, @NonNull IResultReceiver clientReceiver) {
if (activityPresentationInfo == null) {
@@ -340,8 +342,8 @@
mRemoteService.ensureBoundLocked();
final ContentCaptureServerSession newSession = new ContentCaptureServerSession(mLock,
- activityToken, this, componentName, clientReceiver, taskId, displayId, sessionId,
- uid, flags);
+ activityToken, new ActivityId(taskId, shareableActivityToken), this, componentName,
+ clientReceiver, taskId, displayId, sessionId, uid, flags);
if (mMaster.verbose) {
Slog.v(TAG, "startSession(): new session for "
+ ComponentName.flattenToShortString(componentName) + " and id " + sessionId);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 06ab426..9f3045e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -25,6 +25,7 @@
import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_UPDATING;
import android.annotation.NonNull;
+import android.app.assist.ActivityId;
import android.content.ComponentName;
import android.os.Bundle;
import android.os.IBinder;
@@ -75,9 +76,9 @@
public final ComponentName appComponentName;
ContentCaptureServerSession(@NonNull Object lock, @NonNull IBinder activityToken,
- @NonNull ContentCapturePerUserService service, @NonNull ComponentName appComponentName,
- @NonNull IResultReceiver sessionStateReceiver, int taskId, int displayId, int sessionId,
- int uid, int flags) {
+ @NonNull ActivityId activityId, @NonNull ContentCapturePerUserService service,
+ @NonNull ComponentName appComponentName, @NonNull IResultReceiver sessionStateReceiver,
+ int taskId, int displayId, int sessionId, int uid, int flags) {
Preconditions.checkArgument(sessionId != NO_SESSION_ID);
mLock = lock;
mActivityToken = activityToken;
@@ -86,7 +87,7 @@
mId = sessionId;
mUid = uid;
mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
- appComponentName, taskId, displayId, flags);
+ activityId, appComponentName, displayId, flags);
mSessionStateReceiver = sessionStateReceiver;
try {
sessionStateReceiver.asBinder().linkToDeath(() -> onClientDeath(), 0);
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index 00c91fe..57c643b 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.contentsuggestions.ClassificationsRequest;
import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IClassificationsCallback;
@@ -253,6 +254,23 @@
receiver.send(isDisabled ? 0 : 1, null);
}
+ @Override
+ public void resetTemporaryService(@UserIdInt int userId) {
+ ContentSuggestionsManagerService.this.resetTemporaryService(userId);
+ }
+
+ @Override
+ public void setTemporaryService(
+ @UserIdInt int userId, @NonNull String serviceName, int duration) {
+ ContentSuggestionsManagerService.this.setTemporaryService(
+ userId, serviceName, duration);
+ }
+
+ @Override
+ public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+ ContentSuggestionsManagerService.this.setDefaultServiceEnabled(userId, enabled);
+ }
+
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback callback,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f4138d1..a92fac9 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -44,6 +44,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+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_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
@@ -91,7 +92,6 @@
import android.net.IDnsResolver;
import android.net.INetd;
import android.net.INetworkActivityListener;
-import android.net.INetworkManagementEventObserver;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
@@ -194,6 +194,7 @@
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
@@ -214,7 +215,6 @@
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.utils.PriorityDump;
@@ -332,6 +332,7 @@
private INetworkStatsService mStatsService;
private NetworkPolicyManager mPolicyManager;
private NetworkPolicyManagerInternal mPolicyManagerInternal;
+ private final NetdCallback mNetdCallback;
/**
* TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple
@@ -1204,6 +1205,13 @@
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd);
+ mNetdCallback = new NetdCallback();
+ try {
+ mNetd.registerUnsolicitedEventListener(mNetdCallback);
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Error registering event listener :" + e);
+ }
+
mSettingsObserver = new SettingsObserver(mContext, mHandler);
registerSettingsCallbacks();
@@ -1241,6 +1249,7 @@
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
netCap.setSingleUid(uid);
return netCap;
@@ -1255,6 +1264,7 @@
int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > TYPE_NONE) {
netCap.addTransportType(transportType);
@@ -2191,8 +2201,45 @@
"ConnectivityService");
}
+ /**
+ * Performs a strict and comprehensive check of whether a calling package is allowed to
+ * change the state of network, as the condition differs for pre-M, M+, and
+ * privileged/preinstalled apps. The caller is expected to have either the
+ * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
+ * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
+ * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
+ * permission and cannot be revoked. See http://b/23597341
+ *
+ * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
+ * of this app will be updated to the current time.
+ */
private void enforceChangePermission(String callingPkg, String callingAttributionTag) {
- ConnectivityManager.enforceChangePermission(mContext, callingPkg, callingAttributionTag);
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+
+ if (callingPkg == null) {
+ throw new SecurityException("Calling package name is null.");
+ }
+
+ final AppOpsManager appOpsMgr = mContext.getSystemService(AppOpsManager.class);
+ final int uid = mDeps.getCallingUid();
+ final int mode = appOpsMgr.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS, uid,
+ callingPkg, callingAttributionTag, null /* message */);
+
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ return;
+ }
+
+ if ((mode == AppOpsManager.MODE_DEFAULT) && (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED)) {
+ return;
+ }
+
+ throw new SecurityException(callingPkg + " was not granted either of these permissions:"
+ + android.Manifest.permission.CHANGE_NETWORK_STATE + ","
+ + android.Manifest.permission.WRITE_SETTINGS + ".");
}
private void enforceSettingsPermission() {
@@ -8649,6 +8696,14 @@
notifyDataStallSuspected(p, network.getNetId());
}
+ private class NetdCallback extends BaseNetdUnsolicitedEventListener {
+ @Override
+ public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel,
+ long timestampNs, int uid) {
+ mNetworkActivityTracker.setAndReportNetworkActive(isActive, timerLabel, timestampNs);
+ }
+ }
+
private final LegacyNetworkActivityTracker mNetworkActivityTracker;
/**
@@ -8659,7 +8714,6 @@
private static final int NO_UID = -1;
private final Context mContext;
private final INetd mNetd;
- private final INetworkManagementService mNMS;
private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
new RemoteCallbackList<>();
// Indicate the current system default network activity is active or not.
@@ -8682,41 +8736,27 @@
LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
@NonNull INetworkManagementService nms, @NonNull INetd netd) {
mContext = context;
- mNMS = nms;
mNetd = netd;
mHandler = handler;
- try {
- mNMS.registerObserver(mDataActivityObserver);
- } catch (RemoteException e) {
- loge("Error registering observer :" + e);
- }
}
- // TODO: Migrate away the dependency with INetworkManagementEventObserver.
- private final INetworkManagementEventObserver mDataActivityObserver =
- new BaseNetworkObserver() {
- @Override
- public void interfaceClassDataActivityChanged(int transportType, boolean active,
- long tsNanos, int uid) {
- sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
- tsNanos);
- synchronized (mActiveIdleTimers) {
- mNetworkActive = active;
- // If there are no idle timers, it means that system is not monitoring
- // activity, so the system default network for those default network
- // unspecified apps is always considered active.
- //
- // TODO: If the mActiveIdleTimers is empty, netd will actually not send
- // any network activity change event. Whenever this event is received,
- // the mActiveIdleTimers should be always not empty. The legacy behavior
- // is no-op. Remove to refer to mNetworkActive only.
- if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
- mHandler.sendMessage(
- mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
- }
- }
- }
- };
+ public void setAndReportNetworkActive(boolean active, int transportType, long tsNanos) {
+ sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos);
+ synchronized (mActiveIdleTimers) {
+ mNetworkActive = active;
+ // If there are no idle timers, it means that system is not monitoring
+ // activity, so the system default network for those default network
+ // unspecified apps is always considered active.
+ //
+ // TODO: If the mActiveIdleTimers is empty, netd will actually not send
+ // any network activity change event. Whenever this event is received,
+ // the mActiveIdleTimers should be always not empty. The legacy behavior
+ // is no-op. Remove to refer to mNetworkActive only.
+ if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
+ }
+ }
+ }
// The network activity should only be updated from ConnectivityService handler thread
// when mActiveIdleTimers lock is held.
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 84e429d..f2782f6 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -25,9 +25,9 @@
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.SensorPrivacyManager.EXTRA_SENSOR;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
import static android.os.UserHandle.USER_SYSTEM;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
import android.annotation.NonNull;
@@ -406,12 +406,12 @@
*/
@Override
public void setSensorPrivacy(boolean enable) {
+ enforceManageSensorPrivacyPermission();
// Keep the state consistent between all users to make it a single global state
forAllUsers(userId -> setSensorPrivacy(userId, enable));
}
private void setSensorPrivacy(@UserIdInt int userId, boolean enable) {
- enforceSensorPrivacyPermission();
synchronized (mLock) {
mEnabled.put(userId, enable);
persistSensorPrivacyStateLocked();
@@ -421,7 +421,7 @@
@Override
public void setIndividualSensorPrivacy(@UserIdInt int userId, int sensor, boolean enable) {
- enforceSensorPrivacyPermission();
+ enforceManageSensorPrivacyPermission();
synchronized (mLock) {
SparseBooleanArray userIndividualEnabled = mIndividualEnabled.get(userId,
new SparseBooleanArray());
@@ -448,6 +448,7 @@
@Override
public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId, int sensor,
boolean enable) {
+ enforceManageSensorPrivacyPermission();
int parentId = mUserManagerInternal.getProfileParentId(userId);
forAllUsers(userId2 -> {
if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
@@ -460,21 +461,35 @@
* Enforces the caller contains the necessary permission to change the state of sensor
* privacy.
*/
- private void enforceSensorPrivacyPermission() {
- if (mContext.checkCallingOrSelfPermission(
- MANAGE_SENSOR_PRIVACY) == PERMISSION_GRANTED) {
- return;
- }
- throw new SecurityException(
+ private void enforceManageSensorPrivacyPermission() {
+ enforcePermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY,
"Changing sensor privacy requires the following permission: "
+ MANAGE_SENSOR_PRIVACY);
}
/**
+ * Enforces the caller contains the necessary permission to observe changes to the sate of
+ * sensor privacy.
+ */
+ private void enforceObserveSensorPrivacyPermission() {
+ enforcePermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY,
+ "Observing sensor privacy changes requires the following permission: "
+ + android.Manifest.permission.OBSERVE_SENSOR_PRIVACY);
+ }
+
+ private void enforcePermission(String permission, String message) {
+ if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ return;
+ }
+ throw new SecurityException(message);
+ }
+
+ /**
* Returns whether sensor privacy is enabled.
*/
@Override
public boolean isSensorPrivacyEnabled() {
+ enforceObserveSensorPrivacyPermission();
return isSensorPrivacyEnabled(USER_SYSTEM);
}
@@ -486,6 +501,7 @@
@Override
public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
+ enforceObserveSensorPrivacyPermission();
synchronized (mLock) {
SparseBooleanArray states = mIndividualEnabled.get(userId);
if (states == null) {
@@ -703,6 +719,7 @@
*/
@Override
public void addSensorPrivacyListener(ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new NullPointerException("listener cannot be null");
}
@@ -715,6 +732,7 @@
@Override
public void addIndividualSensorPrivacyListener(int userId, int sensor,
ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new NullPointerException("listener cannot be null");
}
@@ -726,6 +744,7 @@
*/
@Override
public void removeSensorPrivacyListener(ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new NullPointerException("listener cannot be null");
}
@@ -735,6 +754,7 @@
@Override
public void suppressIndividualSensorPrivacyReminders(int userId, String packageName,
IBinder token, boolean suppress) {
+ enforceManageSensorPrivacyPermission();
Objects.requireNonNull(packageName);
Objects.requireNonNull(token);
@@ -886,13 +906,13 @@
}
/**
- * Convert a string into a {@link SensorPrivacyManager.IndividualSensor id}.
+ * Convert a string into a {@link SensorPrivacyManager.Sensors.Sensor id}.
*
* @param sensor The name to convert
*
* @return The id corresponding to the name
*/
- private @SensorPrivacyManager.IndividualSensor int sensorStrToId(@Nullable String sensor) {
+ private @SensorPrivacyManager.Sensors.Sensor int sensorStrToId(@Nullable String sensor) {
if (sensor == null) {
return UNKNOWN;
}
@@ -950,7 +970,7 @@
return -1;
}
- enforceSensorPrivacyPermission();
+ enforceManageSensorPrivacyPermission();
synchronized (mLock) {
SparseBooleanArray individualEnabled =
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index c2d8fa2..8a2894c 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -45,14 +45,18 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.Immutable;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
@@ -87,26 +91,30 @@
/** Function to run on binder interface when first bound. */
public interface OnBindRunner {
/** Called to run client code with the binder. */
- void run(IBinder binder, ComponentName service) throws RemoteException;
+ void run(IBinder binder, BoundService service) throws RemoteException;
}
/**
* Information on the service ServiceWatcher has selected as the best option for binding.
*/
- private static final class ServiceInfo implements Comparable<ServiceInfo> {
+ @Immutable
+ public static final class BoundService implements Comparable<BoundService> {
- public static final ServiceInfo NONE = new ServiceInfo(Integer.MIN_VALUE, null,
- UserHandle.USER_NULL, false);
+ public static final BoundService NONE = new BoundService(Integer.MIN_VALUE, null,
+ false, null, -1);
public final int version;
- @Nullable public final ComponentName component;
- @UserIdInt public final int userId;
+ @Nullable
+ public final ComponentName component;
public final boolean serviceIsMultiuser;
+ public final int uid;
+ @Nullable
+ public final Bundle metadata;
- ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
+ BoundService(ResolveInfo resolveInfo) {
Preconditions.checkArgument(resolveInfo.serviceInfo.getComponentName() != null);
- Bundle metadata = resolveInfo.serviceInfo.metaData;
+ metadata = resolveInfo.serviceInfo.metaData;
if (metadata != null) {
version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
serviceIsMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false);
@@ -116,16 +124,17 @@
}
component = resolveInfo.serviceInfo.getComponentName();
- userId = serviceIsMultiuser ? UserHandle.USER_SYSTEM : currentUserId;
+ uid = resolveInfo.serviceInfo.applicationInfo.uid;
}
- private ServiceInfo(int version, @Nullable ComponentName component, int userId,
- boolean serviceIsMultiuser) {
+ private BoundService(int version, @Nullable ComponentName component,
+ boolean serviceIsMultiuser, @Nullable Bundle metadata, int uid) {
Preconditions.checkArgument(component != null || version == Integer.MIN_VALUE);
this.version = version;
this.component = component;
- this.userId = userId;
this.serviceIsMultiuser = serviceIsMultiuser;
+ this.metadata = metadata;
+ this.uid = uid;
}
public @Nullable String getPackageName() {
@@ -137,21 +146,21 @@
if (this == o) {
return true;
}
- if (!(o instanceof ServiceInfo)) {
+ if (!(o instanceof BoundService)) {
return false;
}
- ServiceInfo that = (ServiceInfo) o;
- return version == that.version && userId == that.userId
+ BoundService that = (BoundService) o;
+ return version == that.version && uid == that.uid
&& Objects.equals(component, that.component);
}
@Override
public int hashCode() {
- return Objects.hash(version, component, userId);
+ return Objects.hash(version, component, uid);
}
@Override
- public int compareTo(ServiceInfo that) {
+ public int compareTo(BoundService that) {
// ServiceInfos with higher version numbers always win (having a version number >
// MIN_VALUE implies having a non-null component). if version numbers are equal, a
// non-null component wins over a null component. if the version numbers are equal and
@@ -164,10 +173,11 @@
} else if (component != null && that.component == null) {
ret = 1;
} else {
- if (userId != UserHandle.USER_SYSTEM && that.userId == UserHandle.USER_SYSTEM) {
+ if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM
+ && UserHandle.getUserId(that.uid) == UserHandle.USER_SYSTEM) {
ret = -1;
- } else if (userId == UserHandle.USER_SYSTEM
- && that.userId != UserHandle.USER_SYSTEM) {
+ } else if (UserHandle.getUserId(uid) == UserHandle.USER_SYSTEM
+ && UserHandle.getUserId(that.uid) != UserHandle.USER_SYSTEM) {
ret = 1;
}
}
@@ -180,7 +190,8 @@
if (component == null) {
return "none";
} else {
- return component.toShortString() + "@" + version + "[u" + userId + "]";
+ return component.toShortString() + "@" + version + "[u"
+ + UserHandle.getUserId(uid) + "]";
}
}
}
@@ -227,17 +238,23 @@
}
};
- @Nullable private final OnBindRunner mOnBind;
- @Nullable private final Runnable mOnUnbind;
+ // read/write from handler thread only
+ private final Map<ComponentName, BoundService> mPendingBinds = new ArrayMap<>();
- // write from caller thread only, read anywhere
- private volatile boolean mRegistered;
+ @Nullable
+ private final OnBindRunner mOnBind;
+
+ @Nullable
+ private final Runnable mOnUnbind;
+
+ // read/write from handler thread only
+ private boolean mRegistered;
// read/write from handler thread only
private int mCurrentUserId;
// write from handler thread only, read anywhere
- private volatile ServiceInfo mTargetService;
+ private volatile BoundService mTargetService;
private volatile IBinder mBinder;
public ServiceWatcher(Context context, String action,
@@ -274,7 +291,7 @@
mCurrentUserId = UserHandle.USER_NULL;
- mTargetService = ServiceInfo.NONE;
+ mTargetService = BoundService.NONE;
mBinder = null;
}
@@ -299,6 +316,11 @@
* Starts the process of determining the best matching service and maintaining a binding to it.
*/
public void register() {
+ mHandler.sendMessage(PooledLambda.obtainMessage(ServiceWatcher::registerInternal,
+ ServiceWatcher.this));
+ }
+
+ private void registerInternal() {
Preconditions.checkState(!mRegistered);
mPackageMonitor.register(mContext, UserHandle.ALL, true, mHandler);
@@ -309,6 +331,8 @@
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, intentFilter, null,
mHandler);
+ // TODO: This makes the behavior of the class unpredictable as the caller needs
+ // to know the internal impl detail that calling register would pick the current user.
mCurrentUserId = ActivityManager.getCurrentUser();
mRegistered = true;
@@ -320,6 +344,11 @@
* Stops the process of determining the best matching service and releases any binding.
*/
public void unregister() {
+ mHandler.sendMessage(PooledLambda.obtainMessage(ServiceWatcher::unregisterInternal,
+ ServiceWatcher.this));
+ }
+
+ private void unregisterInternal() {
Preconditions.checkState(mRegistered);
mRegistered = false;
@@ -333,7 +362,7 @@
private void onBestServiceChanged(boolean forceRebind) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- ServiceInfo bestServiceInfo = ServiceInfo.NONE;
+ BoundService bestServiceInfo = BoundService.NONE;
if (mRegistered) {
List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
@@ -344,7 +373,7 @@
if (!mServiceCheckPredicate.test(resolveInfo)) {
continue;
}
- ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
+ BoundService serviceInfo = new BoundService(resolveInfo);
if (serviceInfo.compareTo(bestServiceInfo) > 0) {
bestServiceInfo = serviceInfo;
}
@@ -356,21 +385,22 @@
}
}
- private void rebind(ServiceInfo newServiceInfo) {
+ private void rebind(BoundService newServiceInfo) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- if (!mTargetService.equals(ServiceInfo.NONE)) {
+ if (!mTargetService.equals(BoundService.NONE)) {
if (D) {
Log.d(TAG, "[" + mIntent.getAction() + "] unbinding from " + mTargetService);
}
mContext.unbindService(this);
onServiceDisconnected(mTargetService.component);
- mTargetService = ServiceInfo.NONE;
+ mPendingBinds.remove(mTargetService.component);
+ mTargetService = BoundService.NONE;
}
mTargetService = newServiceInfo;
- if (mTargetService.equals(ServiceInfo.NONE)) {
+ if (mTargetService.equals(BoundService.NONE)) {
return;
}
@@ -381,10 +411,12 @@
Intent bindIntent = new Intent(mIntent).setComponent(mTargetService.component);
if (!mContext.bindServiceAsUser(bindIntent, this,
BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_NOT_VISIBLE,
- mHandler, UserHandle.of(mTargetService.userId))) {
- mTargetService = ServiceInfo.NONE;
+ mHandler, UserHandle.of(UserHandle.getUserId(mTargetService.uid)))) {
+ mTargetService = BoundService.NONE;
Log.e(TAG, getLogPrefix() + " unexpected bind failure - retrying later");
mHandler.postDelayed(() -> onBestServiceChanged(false), RETRY_DELAY_MS);
+ } else {
+ mPendingBinds.put(mTargetService.component, mTargetService);
}
}
@@ -397,10 +429,15 @@
Log.d(TAG, getLogPrefix() + " connected to " + component.toShortString());
}
+ final BoundService boundService = mPendingBinds.remove(component);
+ if (boundService == null) {
+ return;
+ }
+
mBinder = binder;
if (mOnBind != null) {
try {
- mOnBind.run(binder, component);
+ mOnBind.run(binder, boundService);
} catch (RuntimeException | RemoteException e) {
// binders may propagate some specific non-RemoteExceptions from the other side
// through the binder as well - we cannot allow those to crash the system server
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 6be7f05..233a50d 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3338,6 +3338,39 @@
}
}
+ @Override
+ public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) {
+ enforceExternalStorageService();
+
+ mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
+ }
+
+ @Override
+ public void notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason) {
+ enforceExternalStorageService();
+
+ mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason);
+ }
+
+ private boolean isAppIoBlocked(int uid) {
+ return mStorageSessionController.isAppIoBlocked(uid);
+ }
+
+ /**
+ * Enforces that the caller is the {@link ExternalStorageService}
+ *
+ * @throws SecurityException if the caller doesn't have the
+ * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the
+ * {@link ExternalStorageService}
+ */
+ private void enforceExternalStorageService() {
+ enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE);
+ int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+ if (callingAppId != mMediaStoreAuthorityAppId) {
+ throw new SecurityException("Only the ExternalStorageService is permitted");
+ }
+ }
+
/** Not thread safe */
class AppFuseMountScope extends AppFuseBridge.MountScope {
private boolean mMounted = false;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2efc83c..d998ebb 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -20,10 +20,35 @@
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
+import static android.os.PowerWhitelistManager.REASON_ACTIVITY_STARTER;
+import static android.os.PowerWhitelistManager.REASON_ALLOWLISTED_PACKAGE;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
+import static android.os.PowerWhitelistManager.REASON_DEVICE_DEMO_MODE;
+import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_EXEMPTED_PACKAGE;
+import static android.os.PowerWhitelistManager.REASON_FGS_BINDING;
+import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT;
+import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT_UI;
+import static android.os.PowerWhitelistManager.REASON_PROC_STATE_TOP;
+import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_START_ACTIVITY_FLAG;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
+import static android.os.PowerWhitelistManager.REASON_UID_VISIBLE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
+import static android.os.PowerWhitelistManager.reasonCodeToString;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
@@ -43,7 +68,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -86,6 +110,8 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerWhitelistManager;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -130,8 +156,6 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
@@ -152,58 +176,6 @@
private static final boolean SHOW_DUNGEON_NOTIFICATION = false;
- public static final int FGS_FEATURE_DENIED = 0;
- public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
- public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 2;
- public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 3;
- public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 4;
- public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 5;
- public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 6;
- public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION = 7;
- public static final int FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN = 8;
- public static final int FGS_FEATURE_ALLOWED_BY_FGS_TOKEN = 9;
- public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION = 10;
- public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION = 12;
- public static final int FGS_FEATURE_ALLOWED_BY_ALLOWLIST = 13;
- public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 14;
- public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 15;
- public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
- public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
- public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18;
- public static final int FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD = 19;
- public static final int FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES = 20;
- public static final int FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER = 21;
- public static final int FGS_FEATURE_ALLOWED_BY_COMPANION_APP = 22;
- public static final int FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER = 23;
-
- @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
- FGS_FEATURE_DENIED,
- FGS_FEATURE_ALLOWED_BY_UID_STATE,
- FGS_FEATURE_ALLOWED_BY_PROC_STATE,
- FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
- FGS_FEATURE_ALLOWED_BY_FLAG,
- FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
- FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN,
- FGS_FEATURE_ALLOWED_BY_FGS_TOKEN,
- FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_ALLOWLIST,
- FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
- FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
- FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_FGS_BINDING,
- FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE,
- FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD,
- FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES,
- FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER,
- FGS_FEATURE_ALLOWED_BY_COMPANION_APP,
- FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface FgsFeatureRetCode {}
-
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
@@ -275,7 +247,7 @@
AppWidgetManagerInternal mAppWidgetManagerInternal;
- // white listed packageName.
+ // allowlisted packageName.
ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();
// TODO: remove this after feature development is done
@@ -675,7 +647,7 @@
if (fgRequired) {
logFgsBackgroundStart(r);
- if (r.mAllowStartForeground == FGS_FEATURE_DENIED && isBgFgsRestrictionEnabled(r)) {
+ if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
String msg = "startForegroundService() not allowed due to "
+ "mAllowStartForeground false: service "
+ r.shortInstanceName;
@@ -1768,8 +1740,7 @@
if (!ignoreForeground) {
logFgsBackgroundStart(r);
- if (r.mAllowStartForeground == FGS_FEATURE_DENIED
- && isBgFgsRestrictionEnabled(r)) {
+ if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
final String msg = "Service.startForeground() not allowed due to "
+ "mAllowStartForeground false: service "
+ r.shortInstanceName;
@@ -2250,7 +2221,7 @@
psr.mAllowlistManager = false;
for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) {
ServiceRecord sr = psr.getRunningServiceAt(i);
- if (sr.whitelistManager) {
+ if (sr.allowlistManager) {
psr.mAllowlistManager = true;
break;
}
@@ -2261,7 +2232,7 @@
final ProcessServiceRecord psr = service.app.mServices;
psr.stopService(service);
psr.updateBoundClientUids();
- if (service.whitelistManager) {
+ if (service.allowlistManager) {
updateAllowlistManagerLocked(psr);
}
}
@@ -2483,7 +2454,7 @@
clientPsr.setHasAboveClient(true);
}
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
- s.whitelistManager = true;
+ s.allowlistManager = true;
}
if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.setAllowedBgActivityStartsByBinding(true);
@@ -2520,7 +2491,7 @@
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
servicePsr.setTreatLikeActivity(true);
}
- if (s.whitelistManager) {
+ if (s.allowlistManager) {
servicePsr.mAllowlistManager = true;
}
// This could have made the service more important.
@@ -2949,7 +2920,6 @@
final ServiceRestarter res = new ServiceRestarter();
r = new ServiceRecord(mAm, className, name, definingPackageName,
definingUid, filter, sInfo, callingFromFg, res);
- r.mRecentCallingPackage = callingPackage;
res.setService(r);
smap.mServicesByInstanceName.put(name, r);
smap.mServicesByIntent.put(filter, r);
@@ -2978,6 +2948,8 @@
}
}
if (r != null) {
+ r.mRecentCallingPackage = callingPackage;
+ r.mRecentCallingUid = callingUid;
if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName,
r.appInfo.uid)) {
String msg = "association not allowed between packages "
@@ -3440,12 +3412,13 @@
if (r.fgRequired) {
if (DEBUG_FOREGROUND_SERVICE) {
- Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
+ Slog.v(TAG, "Allowlisting " + UserHandle.formatUid(r.appInfo.uid)
+ " for fg-service launch");
}
mAm.tempAllowlistUidLocked(r.appInfo.uid,
- SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch",
- BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
+ SERVICE_START_FOREGROUND_TIMEOUT, PowerWhitelistManager.REASON_SERVICE_LAUNCH,
+ "fg-service-launch", TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ r.mRecentCallingUid);
}
if (!mPendingServices.contains(r)) {
@@ -3551,7 +3524,7 @@
}
}
- if (r.whitelistManager) {
+ if (r.allowlistManager) {
psr.mAllowlistManager = true;
}
@@ -3868,6 +3841,8 @@
r.name.getClassName());
stopServiceAndUpdateAllowlistManagerLocked(r);
if (r.app.getThread() != null) {
+ // Bump the process to the top of LRU list
+ mAm.updateLruProcessLocked(r.app, false, null);
updateServiceForegroundLocked(r.app.mServices, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
@@ -3941,11 +3916,11 @@
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
psr.updateHasAboveClientLocked();
}
- // If this connection requested whitelist management, see if we should
+ // If this connection requested allowlist management, see if we should
// now clear that state.
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
- s.updateWhitelistManager();
- if (!s.whitelistManager && s.app != null) {
+ s.updateAllowlistManager();
+ if (!s.allowlistManager && s.app != null) {
updateAllowlistManagerLocked(s.app.mServices);
}
}
@@ -5400,13 +5375,13 @@
}
if (!r.mAllowWhileInUsePermissionInFgs
- || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
- final @FgsFeatureRetCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
+ || (r.mAllowStartForeground == REASON_DENIED)) {
+ final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != FGS_FEATURE_DENIED);
+ r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
}
- if (r.mAllowStartForeground == FGS_FEATURE_DENIED) {
+ if (r.mAllowStartForeground == REASON_DENIED) {
r.mAllowStartForeground = shouldAllowFgsStartForegroundLocked(allowWhileInUse,
callingPackage, callingPid, callingUid, intent, r,
allowBackgroundActivityStarts);
@@ -5420,37 +5395,37 @@
* @param callingPackage caller app's package name.
* @param callingUid caller app's uid.
* @param r the service to start.
- * @return {@link FgsFeatureRetCode}
+ * @return {@link ReasonCode}
*/
- private @FgsFeatureRetCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
+ private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
int callingPid, int callingUid, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
- int ret = FGS_FEATURE_DENIED;
+ int ret = REASON_DENIED;
final int uidState = mAm.getUidStateLocked(callingUid);
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
// Is the calling UID at PROCESS_STATE_TOP or above?
if (uidState <= PROCESS_STATE_TOP) {
- ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
+ ret = getReasonCodeFromProcState(uidState);
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
// Does the calling UID have any visible activity?
final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid);
if (isCallingUidVisible) {
- ret = FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
+ ret = REASON_UID_VISIBLE;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
// Is the allow activity background start flag on?
if (allowBackgroundActivityStarts) {
- ret = FGS_FEATURE_ALLOWED_BY_FLAG;
+ ret = REASON_START_ACTIVITY_FLAG;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
boolean isCallerSystem = false;
final int callingAppId = UserHandle.getAppId(callingUid);
switch (callingAppId) {
@@ -5466,15 +5441,15 @@
}
if (isCallerSystem) {
- ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
+ ret = REASON_SYSTEM_UID;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, pr -> {
if (pr.uid == callingUid) {
if (pr.getWindowProcessController().areBackgroundFgsStartsAllowed()) {
- return FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER;
+ return REASON_ACTIVITY_STARTER;
}
}
return null;
@@ -5484,35 +5459,35 @@
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
if (r.app != null) {
ActiveInstrumentation instr = r.app.getActiveInstrumentation();
if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
- ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
+ ret = REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
}
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
+ ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
final boolean isAllowedPackage =
mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
if (isAllowedPackage) {
- ret = FGS_FEATURE_ALLOWED_BY_ALLOWLIST;
+ ret = REASON_ALLOWLISTED_PACKAGE;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
// Is the calling UID a device owner app?
final boolean isDeviceOwner = mAm.mInternal.isDeviceOwner(callingUid);
if (isDeviceOwner) {
- ret = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
+ ret = REASON_DEVICE_OWNER;
}
}
return ret;
@@ -5527,38 +5502,40 @@
* @param callingUid caller app's uid.
* @param intent intent to start/bind service.
* @param r the service to start.
- * @return {@link FgsFeatureRetCode}
+ * @return {@link ReasonCode}
*/
- private @FgsFeatureRetCode int shouldAllowFgsStartForegroundLocked(
- @FgsFeatureRetCode int allowWhileInUse, String callingPackage, int callingPid,
+ private @ReasonCode int shouldAllowFgsStartForegroundLocked(
+ @ReasonCode int allowWhileInUse, String callingPackage, int callingPid,
int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) {
int ret = allowWhileInUse;
+ FgsStartTempAllowList.TempFgsAllowListEntry tempAllowListReason =
+ r.mInfoTempFgsAllowListReason = mAm.isAllowlistedForFgsStartLOSP(callingUid);
final StringBuilder sb = new StringBuilder(64);
final int uidState = mAm.getUidStateLocked(callingUid);
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
// Is the calling UID at PROCESS_STATE_TOP or above?
if (uidState <= PROCESS_STATE_TOP) {
sb.append("uidState=").append(uidState);
- ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
+ ret = getReasonCodeFromProcState(uidState);
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> {
if (app.uid == callingUid) {
final ProcessStateRecord state = app.mState;
- if (state.getAllowedStartFgs() != FGS_FEATURE_DENIED) {
+ if (state.getAllowedStartFgs() != REASON_DENIED) {
return state.getAllowedStartFgs();
} else if (state.isAllowedStartFgsState()) {
- return FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+ return getReasonCodeFromProcState(state.getAllowStartFgsState());
} else if (state.areBackgroundFgsStartsAllowedByToken()) {
- return FGS_FEATURE_ALLOWED_BY_FGS_BINDING;
+ return REASON_FGS_BINDING;
} else {
final ActiveInstrumentation instr = app.getActiveInstrumentation();
if (instr != null
&& instr.mHasBackgroundForegroundServiceStartsPermission) {
- return FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION;
+ return REASON_INSTR_BACKGROUND_FGS_PERMISSION;
}
}
}
@@ -5569,55 +5546,59 @@
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
if (mAm.checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid,
callingUid) == PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
+ ret = REASON_BACKGROUND_FGS_PERMISSION;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
if (mAm.checkPermission(SYSTEM_ALERT_WINDOW, callingPid,
callingUid) == PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
+ ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
}
}
- if (ret == FGS_FEATURE_DENIED) {
- if (mAm.isAllowlistedForFgsStartLOSP(callingUid)) {
- // uid is on DeviceIdleController's user/system allowlist
- // or AMS's FgsStartTempAllowList.
- ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
+ if (ret == REASON_DENIED) {
+ FgsStartTempAllowList.TempFgsAllowListEntry entry =
+ mAm.isAllowlistedForFgsStartLOSP(callingUid);
+ if (entry != null) {
+ if (entry == ActivityManagerService.FAKE_TEMP_ALLOWLIST_ENTRY) {
+ ret = REASON_SYSTEM_ALLOW_LISTED;
+ } else {
+ ret = entry.mReasonCode;
+ }
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
if (UserManager.isDeviceInDemoMode(mAm.mContext)) {
- ret = FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE;
+ ret = REASON_DEVICE_DEMO_MODE;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
// Is the calling UID a profile owner app?
final boolean isProfileOwner = mAm.mInternal.isProfileOwner(callingUid);
if (isProfileOwner) {
- ret = FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER;
+ ret = REASON_PROFILE_OWNER;
}
}
// NOTE this should always be the last check.
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
if (isPackageExemptedFromFgsRestriction(r.appInfo.packageName, r.appInfo.uid)
|| isPackageExemptedFromFgsRestriction(callingPackage, callingUid)) {
- ret = FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES;
+ ret = REASON_EXEMPTED_PACKAGE;
}
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (ret == REASON_DENIED) {
final boolean isCompanionApp = mAm.mInternal.isAssociatedCompanionApp(
UserHandle.getUserId(callingUid), callingUid);
if (isCompanionApp) {
- ret = FGS_FEATURE_ALLOWED_BY_COMPANION_APP;
+ ret = REASON_COMPANION_DEVICE_MANAGER;
}
}
@@ -5626,7 +5607,15 @@
+ "; callingUid: " + callingUid
+ "; uidState: " + ProcessList.makeProcStateString(uidState)
+ "; intent: " + intent
- + "; code:" + fgsCodeToString(ret)
+ + "; code:" + reasonCodeToString(ret)
+ + "; tempAllowListReason:<" +
+ (tempAllowListReason == null ? null :
+ (tempAllowListReason.mReason
+ + ",reasonCode:"
+ + reasonCodeToString(tempAllowListReason.mReasonCode)
+ + ",duration:" + tempAllowListReason.mDuration
+ + ",callingUid:" + tempAllowListReason.mCallingUid))
+ + ">"
+ "; extra:" + sb.toString()
+ "; targetSdkVersion:" + r.appInfo.targetSdkVersion
+ "]";
@@ -5660,62 +5649,11 @@
return CompatChanges.isChangeEnabled(FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID, uid);
}
- static String fgsCodeToString(@FgsFeatureRetCode int code) {
- switch (code) {
- case FGS_FEATURE_DENIED:
- return "DENIED";
- case FGS_FEATURE_ALLOWED_BY_UID_STATE:
- return "ALLOWED_BY_UID_STATE";
- case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
- return "ALLOWED_BY_PROC_STATE";
- case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
- return "ALLOWED_BY_UID_VISIBLE";
- case FGS_FEATURE_ALLOWED_BY_FLAG:
- return "ALLOWED_BY_FLAG";
- case FGS_FEATURE_ALLOWED_BY_SYSTEM_UID:
- return "ALLOWED_BY_SYSTEM_UID";
- case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
- return "ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION:
- return "ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN:
- return "ALLOWED_BY_ACTIVITY_TOKEN";
- case FGS_FEATURE_ALLOWED_BY_FGS_TOKEN:
- return "ALLOWED_BY_FGS_TOKEN";
- case FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION:
- return "ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION:
- return "ALLOWED_BY_BACKGROUND_FGS_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_ALLOWLIST:
- return "ALLOWED_BY_ALLOWLIST";
- case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
- return "ALLOWED_BY_DEVICE_OWNER";
- case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
- return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
- case FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION:
- return "ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_FGS_BINDING:
- return "ALLOWED_BY_FGS_BINDING";
- case FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE:
- return "ALLOWED_BY_DEVICE_DEMO_MODE";
- case FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD:
- return "ALLOWED_BY_PROCESS_RECORD";
- case FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES:
- return "FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES";
- case FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER:
- return "ALLOWED_BY_ACTIVITY_STARTER";
- case FGS_FEATURE_ALLOWED_BY_COMPANION_APP:
- return "ALLOWED_BY_COMPANION_APP";
- case FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER:
- return "ALLOWED_BY_PROFILE_OWNER";
- default:
- return "";
- }
- }
-
- private static boolean isFgsBgStart(@FgsFeatureRetCode int code) {
- return code != FGS_FEATURE_ALLOWED_BY_UID_STATE
- && code != FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
+ private static boolean isFgsBgStart(@ReasonCode int code) {
+ return code != REASON_PROC_STATE_PERSISTENT
+ && code != REASON_PROC_STATE_PERSISTENT_UI
+ && code != REASON_PROC_STATE_TOP
+ && code != REASON_UID_VISIBLE;
}
// TODO: remove this notification after feature development is done
@@ -5754,10 +5692,10 @@
}
if (!r.mLoggedInfoAllowStartForeground) {
final String msg = "Background started FGS: "
- + ((r.mAllowStartForeground != FGS_FEATURE_DENIED) ? "Allowed " : "Disallowed ")
+ + ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
+ r.mInfoAllowStartForeground;
Slog.wtfQuiet(TAG, msg);
- if (r.mAllowStartForeground != FGS_FEATURE_DENIED) {
+ if (r.mAllowStartForeground != REASON_DENIED) {
Slog.i(TAG, msg);
} else {
Slog.w(TAG, msg);
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 171b20c..9d1c838 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -68,7 +68,7 @@
static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
- static final boolean DEBUG_WHITELISTS = DEBUG_ALL || false;
+ static final boolean DEBUG_ALLOWLISTS = DEBUG_ALL || false;
static final String POSTFIX_BACKUP = (APPEND_CATEGORY_NAME) ? "_Backup" : "";
static final String POSTFIX_BROADCAST = (APPEND_CATEGORY_NAME) ? "_Broadcast" : "";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 33c0f9d..7cd49497 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -33,7 +33,6 @@
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.AppOpsManager.OP_NONE;
-import static android.app.BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
import static android.content.pm.PackageManager.MATCH_ALL;
@@ -50,8 +49,12 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.BLUETOOTH_UID;
import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.INVALID_UID;
import static android.os.Process.NETWORK_STACK_UID;
import static android.os.Process.NFC_UID;
import static android.os.Process.PHONE_UID;
@@ -101,7 +104,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
@@ -253,6 +256,7 @@
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.PowerWhitelistManager.TempAllowListType;
import android.os.Process;
import android.os.RemoteCallback;
@@ -307,6 +311,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
+import com.android.internal.app.procstats.ProcessState;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.content.PackageHelper;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -624,7 +629,7 @@
*/
private volatile String mDeviceOwnerName;
- private volatile int mDeviceOwnerUid = Process.INVALID_UID;
+ private volatile int mDeviceOwnerUid = INVALID_UID;
/**
* Map userId to its companion app uids.
@@ -1150,13 +1155,13 @@
DeviceIdleInternal mLocalDeviceIdleController;
/**
- * Power-save whitelisted app-ids (not including except-idle-whitelisted ones).
+ * Power-save allowlisted app-ids (not including except-idle-allowlisted ones).
*/
@CompositeRWLock({"this", "mProcLock"})
int[] mDeviceIdleAllowlist = new int[0];
/**
- * Power-save whitelisted app-ids (including except-idle-whitelisted ones).
+ * Power-save allowlisted app-ids (including except-idle-allowlisted ones).
*/
@CompositeRWLock({"this", "mProcLock"})
int[] mDeviceIdleExceptIdleAllowlist = new int[0];
@@ -1172,20 +1177,27 @@
final long duration;
final String tag;
final int type;
+ final @ReasonCode int reasonCode;
- PendingTempAllowlist(int targetUid, long duration, String tag, int type) {
+ PendingTempAllowlist(int targetUid, long duration, @ReasonCode int reasonCode, String tag,
+ int type) {
this.targetUid = targetUid;
this.duration = duration;
this.tag = tag;
this.type = type;
+ this.reasonCode = reasonCode;
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
- proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID,
+ targetUid);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS,
+ duration);
proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TAG, tag);
proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TYPE, type);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.REASON_CODE,
+ reasonCode);
proto.end(token);
}
}
@@ -1199,6 +1211,9 @@
@CompositeRWLock({"this", "mProcLock"})
final FgsStartTempAllowList mFgsStartTempAllowList = new FgsStartTempAllowList();
+ static final FgsStartTempAllowList.TempFgsAllowListEntry FAKE_TEMP_ALLOWLIST_ENTRY = new
+ FgsStartTempAllowList.TempFgsAllowListEntry(Long.MAX_VALUE, Long.MAX_VALUE,
+ REASON_SYSTEM_ALLOW_LISTED, "", INVALID_UID);
/**
* Information about and control over application operations
*/
@@ -1820,6 +1835,15 @@
ncl.start();
}
+ /**
+ * Sets a policy for handling app ops.
+ *
+ * @param appOpsPolicy The policy.
+ */
+ public void setAppOpsPolicy(@Nullable CheckOpsDelegate appOpsPolicy) {
+ mAppOpsService.setAppOpsPolicy(appOpsPolicy);
+ }
+
public IAppOpsService getAppOpsService() {
return mAppOpsService;
}
@@ -3779,10 +3803,11 @@
mi.getTotalUss(), mi.getTotalRss(), false,
ProcessStats.ADD_PSS_EXTERNAL_SLOW, duration);
proc.getPkgList().forEachPackageProcessStats(holder -> {
+ final ProcessState state = holder.state;
FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
+ state != null ? state.getName() : proc.processName,
+ state != null ? state.getPackage() : proc.info.packageName,
mi.getTotalPss(),
mi.getTotalUss(),
mi.getTotalRss(),
@@ -4818,12 +4843,12 @@
}
@Override
- public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,
+ public int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code,
Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
if (target instanceof PendingIntentRecord) {
return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType,
- whitelistToken, finishedReceiver, requiredPermission, options);
+ allowlistToken, finishedReceiver, requiredPermission, options);
} else {
if (intent == null) {
// Weird case: someone has given us their own custom IIntentSender, and now
@@ -4835,7 +4860,7 @@
intent = new Intent(Intent.ACTION_MAIN);
}
try {
- target.send(code, intent, resolvedType, whitelistToken, null,
+ target.send(code, intent, resolvedType, allowlistToken, null,
requiredPermission, options);
} catch (RemoteException e) {
}
@@ -5403,7 +5428,7 @@
}
switch (appop) {
case AppOpsManager.MODE_ALLOWED:
- // If force-background-check is enabled, restrict all apps that aren't whitelisted.
+ // If force-background-check is enabled, restrict all apps that aren't allowlisted.
if (mForceBackgroundCheck &&
!UserHandle.isCore(uid) &&
!isOnDeviceIdleAllowlistLOSP(uid, /*allowExceptIdleToo=*/ true)) {
@@ -5439,7 +5464,7 @@
if (uidOnBackgroundAllowlistLOSP(uid)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
- + " on background whitelist; not restricted in background");
+ + " on background allowlist; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
}
@@ -5448,7 +5473,7 @@
if (isOnDeviceIdleAllowlistLOSP(uid, /*allowExceptIdleToo=*/ false)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
- + " on idle whitelist; not restricted in background");
+ + " on idle allowlist; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
}
@@ -5536,10 +5561,19 @@
|| mPendingTempAllowlist.indexOfKey(uid) >= 0;
}
+ /**
+ * Is the uid allowlisted to start FGS?
+ * @param uid
+ * @return a TempAllowListEntry if the uid is allowed.
+ * null if the uid is not allowed.
+ */
+ @Nullable
@GuardedBy(anyOf = {"this", "mProcLock"})
- boolean isAllowlistedForFgsStartLOSP(int uid) {
- return Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, UserHandle.getAppId(uid)) >= 0
- || mFgsStartTempAllowList.isAllowed(uid);
+ FgsStartTempAllowList.TempFgsAllowListEntry isAllowlistedForFgsStartLOSP(int uid) {
+ if (Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, UserHandle.getAppId(uid)) >= 0) {
+ return FAKE_TEMP_ALLOWLIST_ENTRY;
+ }
+ return mFgsStartTempAllowList.getAllowedDurationAndReason(uid);
}
/**
@@ -6011,13 +6045,13 @@
}
@Override
- public void backgroundWhitelistUid(final int uid) {
+ public void backgroundAllowlistUid(final int uid) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the OS may call backgroundWhitelistUid()");
+ throw new SecurityException("Only the OS may call backgroundAllowlistUid()");
}
if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "Adding uid " + uid + " to bg uid whitelist");
+ Slog.i(TAG, "Adding uid " + uid + " to bg uid allowlist");
}
synchronized (this) {
synchronized (mProcLock) {
@@ -7214,6 +7248,9 @@
final long memoryGrowthThreshold =
Math.max(totalMemoryInKb / 100, MINIMUM_MEMORY_GROWTH_THRESHOLD);
mProcessList.forEachLruProcessesLOSP(false, proc -> {
+ if (proc.getThread() == null) {
+ return;
+ }
final ProcessProfileRecord pr = proc.mProfile;
final ProcessStateRecord state = proc.mState;
final int setProcState = state.getSetProcState();
@@ -8257,7 +8294,7 @@
if (!TextUtils.isEmpty(packageName)) {
final int uid = enforceDumpPermissionForPackage(packageName, userId, callingUid,
"getHistoricalProcessExitReasons");
- if (uid != Process.INVALID_UID) {
+ if (uid != INVALID_UID) {
mProcessList.mAppExitInfoTracker.getExitInfo(
packageName, uid, pid, maxNum, results);
tombstoneService.collectTombstones(results, uid, pid, maxNum);
@@ -8291,7 +8328,7 @@
int enforceDumpPermissionForPackage(String packageName, int userId, int callingUid,
String function) {
final long identity = Binder.clearCallingIdentity();
- int uid = Process.INVALID_UID;
+ int uid = INVALID_UID;
try {
uid = mPackageManagerInt.getPackageUid(packageName,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
@@ -9183,6 +9220,8 @@
pw.println(ptw.tag);
pw.print(" ");
pw.print(ptw.type);
+ pw.print(" ");
+ pw.print(ptw.reasonCode);
}
}
}
@@ -10368,6 +10407,8 @@
}
endTime = SystemClock.currentThreadTimeMillis();
hasSwapPss = mi.hasSwappedOutPss;
+ memtrackGraphics = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS);
+ memtrackGl = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GL);
} else {
reportType = ProcessStats.ADD_PSS_EXTERNAL;
startTime = SystemClock.currentThreadTimeMillis();
@@ -10519,6 +10560,8 @@
if (!Debug.getMemoryInfo(st.pid, info)) {
return;
}
+ memtrackGraphics = info.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS);
+ memtrackGl = info.getOtherPrivate(Debug.MemoryInfo.OTHER_GL);
} else {
long pss = Debug.getPss(st.pid, tmpLong, memtrackTmp);
if (pss == 0) {
@@ -12536,7 +12579,7 @@
BroadcastOptions brOptions = null;
if (bOptions != null) {
brOptions = new BroadcastOptions(bOptions);
- if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
+ if (brOptions.getTemporaryAppAllowlistDuration() > 0) {
// See if the caller is allowed to do this. Note we are checking against
// the actual real caller (not whoever provided the operation as say a
// PendingIntent), because that who is actually supplied the arguments.
@@ -13969,6 +14012,9 @@
final long uptimeSince = curUptime - mLastPowerCheckUptime;
mLastPowerCheckUptime = curUptime;
mProcessList.forEachLruProcessesLOSP(false, app -> {
+ if (app.getThread() == null) {
+ return;
+ }
if (app.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_HOME) {
int cpuLimit;
long checkDur = curUptime - app.mState.getWhenUnimportant();
@@ -14070,11 +14116,12 @@
mBatteryStatsService.reportExcessiveCpu(app.info.uid, app.processName,
uptimeSince, cputimeUsed);
app.getPkgList().forEachPackageProcessStats(holder -> {
+ final ProcessState state = holder.state;
FrameworkStatsLog.write(
FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED,
app.info.uid,
processName,
- holder.state.getPackage(),
+ state != null ? state.getPackage() : app.info.packageName,
holder.appVersion);
});
return true;
@@ -14414,8 +14461,8 @@
*/
@GuardedBy("this")
void tempAllowlistForPendingIntentLocked(int callerPid, int callerUid, int targetUid,
- long duration, int type, String tag) {
- if (DEBUG_WHITELISTS) {
+ long duration, int type, @ReasonCode int reasonCode, String reason) {
+ if (DEBUG_ALLOWLISTS) {
Slog.d(TAG, "tempAllowlistForPendingIntentLocked(" + callerPid + ", " + callerUid + ", "
+ targetUid + ", " + duration + ", " + type + ")");
}
@@ -14434,7 +14481,7 @@
!= PackageManager.PERMISSION_GRANTED
&& checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callerPid,
callerUid) != PackageManager.PERMISSION_GRANTED) {
- if (DEBUG_WHITELISTS) {
+ if (DEBUG_ALLOWLISTS) {
Slog.d(TAG, "tempAllowlistForPendingIntentLocked() for target " + targetUid
+ ": pid " + callerPid + " is not allowed");
}
@@ -14443,22 +14490,23 @@
}
}
- tempAllowlistUidLocked(targetUid, duration, tag, type);
+ tempAllowlistUidLocked(targetUid, duration, reasonCode, reason, type, callerUid);
}
/**
* Allowlists {@code targetUid} to temporarily bypass Power Save mode.
*/
@GuardedBy("this")
- void tempAllowlistUidLocked(int targetUid, long duration, String tag, int type) {
+ void tempAllowlistUidLocked(int targetUid, long duration, @ReasonCode int reasonCode,
+ String reason, int type, int callingUid) {
synchronized (mProcLock) {
mPendingTempAllowlist.put(targetUid,
- new PendingTempAllowlist(targetUid, duration, tag, type));
+ new PendingTempAllowlist(targetUid, duration, reasonCode, reason, type));
setUidTempAllowlistStateLSP(targetUid, true);
mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget();
- if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
- mFgsStartTempAllowList.add(targetUid, duration);
+ if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+ mFgsStartTempAllowList.add(targetUid, duration, reasonCode, reason, callingUid);
}
}
}
@@ -14484,7 +14532,7 @@
for (int i = 0; i < N; i++) {
PendingTempAllowlist ptw = list[i];
mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid,
- ptw.duration, ptw.type, true, ptw.tag);
+ ptw.duration, ptw.type, true, ptw.reasonCode, ptw.tag);
}
}
@@ -15072,10 +15120,10 @@
}
@Override
- public void setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken,
- long duration, int type) {
- mPendingIntentController.setPendingIntentWhitelistDuration(target, whitelistToken,
- duration, type);
+ public void setPendingIntentAllowlistDuration(IIntentSender target, IBinder allowlistToken,
+ long duration, int type, @ReasonCode int reasonCode, @Nullable String reason) {
+ mPendingIntentController.setPendingIntentAllowlistDuration(target, allowlistToken,
+ duration, type, reasonCode, reason);
}
@Override
@@ -15085,32 +15133,32 @@
@Override
public void setPendingIntentAllowBgActivityStarts(IIntentSender target,
- IBinder whitelistToken, int flags) {
+ IBinder allowlistToken, int flags) {
if (!(target instanceof PendingIntentRecord)) {
Slog.w(TAG, "setPendingIntentAllowBgActivityStarts():"
+ " not a PendingIntentRecord: " + target);
return;
}
synchronized (ActivityManagerService.this) {
- ((PendingIntentRecord) target).setAllowBgActivityStarts(whitelistToken, flags);
+ ((PendingIntentRecord) target).setAllowBgActivityStarts(allowlistToken, flags);
}
}
@Override
public void clearPendingIntentAllowBgActivityStarts(IIntentSender target,
- IBinder whitelistToken) {
+ IBinder allowlistToken) {
if (!(target instanceof PendingIntentRecord)) {
Slog.w(TAG, "clearPendingIntentAllowBgActivityStarts():"
+ " not a PendingIntentRecord: " + target);
return;
}
synchronized (ActivityManagerService.this) {
- ((PendingIntentRecord) target).clearAllowBgActivityStarts(whitelistToken);
+ ((PendingIntentRecord) target).clearAllowBgActivityStarts(allowlistToken);
}
}
@Override
- public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
+ public void setDeviceIdleAllowlist(int[] allAppids, int[] exceptIdleAppids) {
synchronized (ActivityManagerService.this) {
synchronized (mProcLock) {
mDeviceIdleAllowlist = allAppids;
@@ -15120,17 +15168,19 @@
}
@Override
- public void updateDeviceIdleTempWhitelist(int[] appids, int changingUid, boolean adding,
- long durationMs, @TempAllowListType int type) {
+ public void updateDeviceIdleTempAllowlist(int[] appids, int changingUid, boolean adding,
+ long durationMs, @TempAllowListType int type, @ReasonCode int reasonCode,
+ @Nullable String reason, int callingUid) {
synchronized (ActivityManagerService.this) {
synchronized (mProcLock) {
mDeviceIdleTempAllowlist = appids;
if (adding) {
- if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
- mFgsStartTempAllowList.add(changingUid, durationMs);
+ if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+ mFgsStartTempAllowList.add(changingUid, durationMs, reasonCode, reason,
+ callingUid);
}
+ setAppIdTempAllowlistStateLSP(changingUid, adding);
}
- setAppIdTempAllowlistStateLSP(changingUid, adding);
}
}
}
@@ -15491,11 +15541,11 @@
}
@Override
- public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
- long duration, int type, String tag) {
+ public void tempAllowlistForPendingIntent(int callerPid, int callerUid, int targetUid,
+ long duration, int type, @ReasonCode int reasonCode, String reason) {
synchronized (ActivityManagerService.this) {
ActivityManagerService.this.tempAllowlistForPendingIntentLocked(
- callerPid, callerUid, targetUid, duration, type, tag);
+ callerPid, callerUid, targetUid, duration, type, reasonCode, reason);
}
}
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 48222cb..a9e5571 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -18,10 +18,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
@@ -138,19 +135,6 @@
findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE);
}
- @Override
- public void onStart() {
- super.onStart();
- getContext().registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- getContext().unregisterReceiver(mReceiver);
- }
-
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
setResult(msg.what);
@@ -204,15 +188,6 @@
}
}
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
- cancel();
- }
- }
- };
-
static class Data {
AppErrorResult result;
int taskId;
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 77d2898..b233a2c 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -181,6 +181,11 @@
}
};
+ @Override
+ protected void closeDialog() {
+ mHandler.obtainMessage(FORCE_CLOSE).sendToTarget();
+ }
+
static class Data {
final ProcessRecord proc;
final ApplicationInfo aInfo;
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index c8630fa..f8494d8 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1327,6 +1327,8 @@
// Get a list of Stats that have vsize > 0
final List<ProcessCpuTracker.Stats> stats = getCpuStats(st -> st.vsize > 0);
final int statsCount = stats.size();
+ long totalMemtrackGraphics = 0;
+ long totalMemtrackGl = 0;
for (int i = 0; i < statsCount; i++) {
ProcessCpuTracker.Stats st = stats.get(i);
long pss = Debug.getPss(st.pid, swaptrackTmp, memtrackTmp);
@@ -1337,6 +1339,8 @@
mi.pss = pss;
mi.swapPss = swaptrackTmp[1];
mi.memtrack = memtrackTmp[0];
+ totalMemtrackGraphics += memtrackTmp[1];
+ totalMemtrackGl += memtrackTmp[2];
memInfos.add(mi);
}
}
@@ -1345,20 +1349,18 @@
long totalPss = 0;
long totalSwapPss = 0;
long totalMemtrack = 0;
- long totalMemtrackGraphics = 0;
- long totalMemtrackGl = 0;
for (int i = 0, size = memInfos.size(); i < size; i++) {
ProcessMemInfo mi = memInfos.get(i);
if (mi.pss == 0) {
mi.pss = Debug.getPss(mi.pid, swaptrackTmp, memtrackTmp);
mi.swapPss = swaptrackTmp[1];
mi.memtrack = memtrackTmp[0];
+ totalMemtrackGraphics += memtrackTmp[1];
+ totalMemtrackGl += memtrackTmp[2];
}
totalPss += mi.pss;
totalSwapPss += mi.swapPss;
totalMemtrack += mi.memtrack;
- totalMemtrackGraphics += memtrackTmp[1];
- totalMemtrackGl += memtrackTmp[2];
}
Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
@Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
diff --git a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 3ce2471..262e795 100644
--- a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -61,6 +61,11 @@
public void onStop() {
}
+ @Override
+ protected void closeDialog() {
+ /* Do nothing */
+ }
+
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index aabb587..7b5f2cd 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -16,16 +16,19 @@
package com.android.server.am;
-import com.android.internal.R;
-
import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.widget.Button;
+import com.android.internal.R;
+
public class BaseErrorDialog extends AlertDialog {
private static final int ENABLE_BUTTONS = 0;
private static final int DISABLE_BUTTONS = 1;
@@ -44,10 +47,19 @@
getWindow().setAttributes(attrs);
}
+ @Override
public void onStart() {
super.onStart();
mHandler.sendEmptyMessage(DISABLE_BUTTONS);
mHandler.sendMessageDelayed(mHandler.obtainMessage(ENABLE_BUTTONS), 1000);
+ getContext().registerReceiver(mReceiver,
+ new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ getContext().unregisterReceiver(mReceiver);
}
public boolean dispatchKeyEvent(KeyEvent event) {
@@ -84,4 +96,24 @@
}
}
};
+
+ /**
+ * Called when received ACTION_CLOSE_SYSTEM_DIALOGS.
+ */
+ protected void closeDialog() {
+ if (mCancelable) {
+ cancel();
+ } else {
+ dismiss();
+ }
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ closeDialog();
+ }
+ }
+ };
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 34ff774..2906193 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -22,6 +22,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.*;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -43,6 +44,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerWhitelistManager;
import android.os.PowerWhitelistManager.TempAllowListType;
import android.os.Process;
import android.os.RemoteException;
@@ -903,8 +905,9 @@
return false;
}
- final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r,
- @TempAllowListType int type) {
+ final void scheduleTempAllowlistLocked(int uid, long duration, BroadcastRecord r,
+ @TempAllowListType int type, @PowerWhitelistManager.ReasonCode int reasonCode,
+ @Nullable String reason) {
if (duration > Integer.MAX_VALUE) {
duration = Integer.MAX_VALUE;
}
@@ -926,10 +929,11 @@
b.append(r.intent.getData());
}
if (DEBUG_BROADCAST) {
- Slog.v(TAG, "Broadcast temp whitelist uid=" + uid + " duration=" + duration
+ Slog.v(TAG, "Broadcast temp allowlist uid=" + uid + " duration=" + duration
+ " type=" + type + " : " + b.toString());
}
- mService.tempAllowlistUidLocked(uid, duration, b.toString(), type);
+ mService.tempAllowlistUidLocked(uid, duration, reasonCode, b.toString(), type,
+ r.callingUid);
}
/**
@@ -1332,10 +1336,12 @@
// r is guaranteed ordered at this point, so we know finishReceiverLocked()
// will get a callback and handle the activity start token lifecycle.
}
- if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
- scheduleTempWhitelistLocked(filter.owningUid,
- brOptions.getTemporaryAppWhitelistDuration(), r,
- brOptions.getTemporaryAppWhitelistType());
+ if (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0) {
+ scheduleTempAllowlistLocked(filter.owningUid,
+ brOptions.getTemporaryAppAllowlistDuration(), r,
+ brOptions.getTemporaryAppAllowlistType(),
+ brOptions.getTemporaryAppAllowlistReasonCode(),
+ brOptions.getTemporaryAppAllowlistReason());
}
}
return;
@@ -1619,11 +1625,13 @@
}
final boolean isActivityCapable =
- (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0);
+ (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0);
if (isActivityCapable) {
- scheduleTempWhitelistLocked(receiverUid,
- brOptions.getTemporaryAppWhitelistDuration(), r,
- brOptions.getTemporaryAppWhitelistType());
+ scheduleTempAllowlistLocked(receiverUid,
+ brOptions.getTemporaryAppAllowlistDuration(), r,
+ brOptions.getTemporaryAppAllowlistType(),
+ brOptions.getTemporaryAppAllowlistReasonCode(),
+ brOptions.getTemporaryAppAllowlistReason());
}
// Broadcast is being executed, its package can't be stopped.
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index a34163c..c5f082a 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -536,18 +536,6 @@
}
/**
- * Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
- * but aren't removed from the freezer. While in this state, processes can be added or removed
- * by using Process.setProcessFrozen(), but they wouldn't be actually frozen until the freezer
- * is enabled. If enable == true all processes in the freezer are frozen.
- *
- * @param enable Specify whether to enable (true) or disable (false) the freezer.
- *
- * @hide
- */
- private static native void enableFreezerInternal(boolean enable);
-
- /**
* Informs binder that a process is about to be frozen. If freezer is enabled on a process via
* this method, this method will synchronously dispatch all pending transactions to the
* specified pid. This method will not add significant latencies when unfreezing.
@@ -590,10 +578,6 @@
if (state == '1' || state == '0') {
supported = true;
- // This is a workaround after reverting the cgroup v2 uid/pid hierarchy due to
- // http://b/179006802.
- // TODO: remove once the uid/pid hierarchy is restored
- enableFreezerInternal(true);
} else {
Slog.e(TAG_AM, "unexpected value in cgroup.freeze");
}
diff --git a/services/core/java/com/android/server/am/FgsStartTempAllowList.java b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
index 4d8749c..1f897b5 100644
--- a/services/core/java/com/android/server/am/FgsStartTempAllowList.java
+++ b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
@@ -18,24 +18,53 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import android.annotation.Nullable;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.SystemClock;
import android.util.Slog;
-import android.util.SparseLongArray;
+import android.util.SparseArray;
/**
* List of uids that are temporarily allowed to start FGS from background.
*/
final class FgsStartTempAllowList {
private static final int MAX_SIZE = 100;
+
+ public static final class TempFgsAllowListEntry {
+ final long mExpirationTime;
+ final long mDuration;
+ final @ReasonCode int mReasonCode;
+ final String mReason;
+ final int mCallingUid;
+
+ TempFgsAllowListEntry(long expirationTime, long duration, @ReasonCode int reasonCode,
+ String reason, int callingUid) {
+ mExpirationTime = expirationTime;
+ mDuration = duration;
+ mReasonCode = reasonCode;
+ mReason = reason;
+ mCallingUid = callingUid;
+ }
+ }
+
/**
- * The key is the uid, the value is expiration elapse time in ms of this temp-allowed uid.
+ * The key is the uid, the value is a TempAllowListEntry.
*/
- private final SparseLongArray mTempAllowListFgs = new SparseLongArray();
+ private final SparseArray<TempFgsAllowListEntry> mTempAllowListFgs = new SparseArray<>();
FgsStartTempAllowList() {
}
- void add(int uid, long duration) {
+ /**
+ * Add a uid and its duration with reason into the FGS temp-allowlist.
+ * @param uid
+ * @param duration temp-allowlisted duration in milliseconds.
+ * @param reason A human-readable reason for logging purposes.
+ * @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
+ * is true.
+ */
+ void add(int uid, long duration, @ReasonCode int reasonCode, @Nullable String reason,
+ int callingUid) {
if (duration <= 0) {
Slog.e(TAG_AM, "FgsStartTempAllowList bad duration:" + duration + " uid: "
+ uid);
@@ -48,26 +77,36 @@
}
final long now = SystemClock.elapsedRealtime();
for (int index = mTempAllowListFgs.size() - 1; index >= 0; index--) {
- if (mTempAllowListFgs.valueAt(index) < now) {
+ if (mTempAllowListFgs.valueAt(index).mExpirationTime < now) {
mTempAllowListFgs.removeAt(index);
}
}
- final long existingExpirationTime = mTempAllowListFgs.get(uid, -1);
+ final TempFgsAllowListEntry existing = mTempAllowListFgs.get(uid);
final long expirationTime = now + duration;
- if (existingExpirationTime == -1 || existingExpirationTime < expirationTime) {
- mTempAllowListFgs.put(uid, expirationTime);
+ if (existing == null || existing.mExpirationTime < expirationTime) {
+ mTempAllowListFgs.put(uid,
+ new TempFgsAllowListEntry(expirationTime, duration, reasonCode,
+ reason == null ? "" : reason, callingUid));
}
}
- boolean isAllowed(int uid) {
+ /**
+ * Is this uid temp-allowlisted to start FGS.
+ * @param uid
+ * @return If uid is in the temp-allowlist, return the {@link TempFgsAllowListEntry}; If not in
+ * temp-allowlist, return null.
+ */
+ @Nullable
+ TempFgsAllowListEntry getAllowedDurationAndReason(int uid) {
final int index = mTempAllowListFgs.indexOfKey(uid);
if (index < 0) {
- return false;
- } else if (mTempAllowListFgs.valueAt(index) < SystemClock.elapsedRealtime()) {
+ return null;
+ } else if (mTempAllowListFgs.valueAt(index).mExpirationTime
+ < SystemClock.elapsedRealtime()) {
mTempAllowListFgs.removeAt(index);
- return false;
+ return null;
} else {
- return true;
+ return mTempAllowListFgs.valueAt(index);
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index b956e30..06e879b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -42,6 +42,7 @@
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -52,7 +53,6 @@
import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_DENIED;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
@@ -522,8 +522,6 @@
computeOomAdjLSP(app, cachedAdj, TOP_APP, doingAll, now, false, true);
- boolean success = applyOomAdjLSP(app, doingAll, now, SystemClock.elapsedRealtime());
-
if (uidRec != null) {
// After uidRec.reset() above, for UidRecord with multiple processes (ProcessRecord),
// we need to apply all ProcessRecord into UidRecord.
@@ -540,7 +538,7 @@
}
}
- return success;
+ return applyOomAdjLSP(app, doingAll, now, SystemClock.elapsedRealtime());
}
/**
@@ -1968,7 +1966,7 @@
int clientProcState = cstate.getCurRawProcState();
// pass client's mAllowStartFgs to the app if client is not persistent process.
- if (cstate.getAllowedStartFgs() != FGS_FEATURE_DENIED
+ if (cstate.getAllowedStartFgs() != REASON_DENIED
&& cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) {
state.setAllowStartFgs(cstate.getAllowedStartFgs());
}
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index 42172bf..534bd84 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -36,6 +36,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerWhitelistManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -300,15 +301,16 @@
}
}
- void setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken,
- long duration, int type) {
+ void setPendingIntentAllowlistDuration(IIntentSender target, IBinder allowlistToken,
+ long duration, int type, @PowerWhitelistManager.ReasonCode int reasonCode,
+ @Nullable String reason) {
if (!(target instanceof PendingIntentRecord)) {
Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target);
return;
}
synchronized (mLock) {
- ((PendingIntentRecord) target).setWhitelistDurationLocked(whitelistToken, duration,
- type);
+ ((PendingIntentRecord) target).setAllowlistDurationLocked(allowlistToken, duration,
+ type, reasonCode, reason);
}
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 0eb48f6..51666ac 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -31,13 +31,14 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.PowerWhitelistManager;
+import android.os.PowerWhitelistManager.ReasonCode;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Pair;
import android.util.Slog;
import android.util.TimeUtils;
@@ -67,7 +68,7 @@
* milliseconds, Integer is allowlist type defined at
* {@link android.os.PowerWhitelistManager.TempAllowListType}
*/
- private ArrayMap<IBinder, Pair<Long, Integer>> mWhitelistDuration;
+ private ArrayMap<IBinder, TempAllowListDuration> mAllowlistDuration;
private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();
@@ -214,6 +215,21 @@
}
}
+ static final class TempAllowListDuration {
+ long duration;
+ int type;
+ @ReasonCode int reasonCode;
+ @Nullable String reason;
+
+ TempAllowListDuration(long _duration, int _type, @ReasonCode int _reasonCode,
+ String _reason) {
+ duration = _duration;
+ type = _type;
+ reasonCode = _reasonCode;
+ reason = _reason;
+ }
+ }
+
PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) {
controller = _controller;
key = _k;
@@ -221,18 +237,19 @@
ref = new WeakReference<>(this);
}
- void setWhitelistDurationLocked(IBinder whitelistToken, long duration, int type) {
+ void setAllowlistDurationLocked(IBinder allowlistToken, long duration, int type,
+ @ReasonCode int reasonCode, @Nullable String reason) {
if (duration > 0) {
- if (mWhitelistDuration == null) {
- mWhitelistDuration = new ArrayMap<>();
+ if (mAllowlistDuration == null) {
+ mAllowlistDuration = new ArrayMap<>();
}
- mWhitelistDuration.put(whitelistToken, new Pair(duration, type));
- } else if (mWhitelistDuration != null) {
- mWhitelistDuration.remove(whitelistToken);
- if (mWhitelistDuration.size() <= 0) {
- mWhitelistDuration = null;
+ mAllowlistDuration.put(allowlistToken,
+ new TempAllowListDuration(duration, type, reasonCode, reason));
+ } else if (mAllowlistDuration != null) {
+ mAllowlistDuration.remove(allowlistToken);
+ if (mAllowlistDuration.size() <= 0) {
+ mAllowlistDuration = null;
}
-
}
this.stringName = null;
}
@@ -280,25 +297,25 @@
return listeners;
}
- public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
+ sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver,
requiredPermission, null, null, 0, 0, 0, options);
}
- public int sendWithResult(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ public int sendWithResult(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- return sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
+ return sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver,
requiredPermission, null, null, 0, 0, 0, options);
}
- public int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
if (intent != null) intent.setDefusable(true);
if (options != null) options.setDefusable(true);
- Pair<Long, Integer> duration = null;
+ TempAllowListDuration duration = null;
Intent finalIntent = null;
Intent[] allIntents = null;
String[] allResolvedTypes = null;
@@ -347,8 +364,8 @@
mergedOptions.setCallerOptions(opts);
}
- if (mWhitelistDuration != null) {
- duration = mWhitelistDuration.get(whitelistToken);
+ if (mAllowlistDuration != null) {
+ duration = mAllowlistDuration.get(allowlistToken);
}
if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY
@@ -377,7 +394,9 @@
try {
if (duration != null) {
StringBuilder tag = new StringBuilder(64);
- tag.append("pendingintent:");
+ tag.append("setPendingIntentAllowlistDuration,reason:");
+ tag.append(duration.reason == null ? "" : duration.reason);
+ tag.append(",pendingintent:");
UserHandle.formatUid(tag, callingUid);
tag.append(":");
if (finalIntent.getAction() != null) {
@@ -387,8 +406,8 @@
} else if (finalIntent.getData() != null) {
tag.append(finalIntent.getData().toSafeString());
}
- controller.mAmInternal.tempWhitelistForPendingIntent(callingPid, callingUid,
- uid, duration.first, duration.second, tag.toString());
+ controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid,
+ uid, duration.duration, duration.type, duration.reasonCode, tag.toString());
}
boolean sendFinish = finishedReceiver != null;
@@ -417,7 +436,8 @@
allIntents, allResolvedTypes, resultTo, mergedOptions, userId,
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
- mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
+ mAllowBgActivityStartsForActivitySender.contains(
+ allowlistToken));
} else {
res = controller.mAtmInternal.startActivityInPackage(uid, callingPid,
callingUid, key.packageName, key.featureId, finalIntent,
@@ -426,7 +446,7 @@
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
mAllowBgActivityStartsForActivitySender.contains(
- whitelistToken));
+ allowlistToken));
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
@@ -439,8 +459,8 @@
case ActivityManager.INTENT_SENDER_BROADCAST:
try {
final boolean allowedByToken =
- mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken);
- final IBinder bgStartsToken = (allowedByToken) ? whitelistToken : null;
+ mAllowBgActivityStartsForBroadcastSender.contains(allowlistToken);
+ final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
// If a completion callback has been requested, require
// that the broadcast be delivered synchronously
@@ -460,8 +480,8 @@
case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
try {
final boolean allowedByToken =
- mAllowBgActivityStartsForServiceSender.contains(whitelistToken);
- final IBinder bgStartsToken = (allowedByToken) ? whitelistToken : null;
+ mAllowBgActivityStartsForServiceSender.contains(allowlistToken);
+ final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
@@ -533,18 +553,23 @@
pw.print(prefix); pw.print("sent="); pw.print(sent);
pw.print(" canceled="); pw.println(canceled);
}
- if (mWhitelistDuration != null) {
+ if (mAllowlistDuration != null) {
pw.print(prefix);
- pw.print("whitelistDuration=");
- for (int i = 0; i < mWhitelistDuration.size(); i++) {
+ pw.print("allowlistDuration=");
+ for (int i = 0; i < mAllowlistDuration.size(); i++) {
if (i != 0) {
pw.print(", ");
}
- pw.print(Integer.toHexString(System.identityHashCode(mWhitelistDuration.keyAt(i))));
+ TempAllowListDuration entry = mAllowlistDuration.valueAt(i);
+ pw.print(Integer.toHexString(System.identityHashCode(mAllowlistDuration.keyAt(i))));
pw.print(":");
- TimeUtils.formatDuration(mWhitelistDuration.valueAt(i).first, pw);
+ TimeUtils.formatDuration(entry.duration, pw);
pw.print("/");
- pw.print(mWhitelistDuration.valueAt(i).second);
+ pw.print(entry.type);
+ pw.print("/");
+ pw.print(PowerWhitelistManager.reasonCodeToString(entry.reasonCode));
+ pw.print("/");
+ pw.print(entry.reason);
}
pw.println();
}
@@ -572,18 +597,23 @@
}
sb.append(' ');
sb.append(key.typeName());
- if (mWhitelistDuration != null) {
- sb.append( " (whitelist: ");
- for (int i = 0; i < mWhitelistDuration.size(); i++) {
+ if (mAllowlistDuration != null) {
+ sb.append(" (allowlist: ");
+ for (int i = 0; i < mAllowlistDuration.size(); i++) {
if (i != 0) {
sb.append(",");
}
+ TempAllowListDuration entry = mAllowlistDuration.valueAt(i);
sb.append(Integer.toHexString(System.identityHashCode(
- mWhitelistDuration.keyAt(i))));
+ mAllowlistDuration.keyAt(i))));
sb.append(":");
- TimeUtils.formatDuration(mWhitelistDuration.valueAt(i).first, sb);
+ TimeUtils.formatDuration(entry.duration, sb);
sb.append("/");
- sb.append(mWhitelistDuration.valueAt(i).second);
+ sb.append(entry.type);
+ sb.append("/");
+ sb.append(PowerWhitelistManager.reasonCodeToString(entry.reasonCode));
+ sb.append("/");
+ sb.append(entry.reason);
}
sb.append(")");
}
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 60b2467..984fe40 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -17,6 +17,8 @@
package com.android.server.am;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerWhitelistManager.REASON_PRE_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -117,9 +119,9 @@
duration = amInternal.getBootTimeTempAllowListDuration();
}
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
- bOptions.setTemporaryAppWhitelistDuration(
- BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- duration);
+ bOptions.setTemporaryAppAllowlist(duration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_PRE_BOOT_COMPLETED, "");
synchronized (mService) {
mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 499fbcb..6d783fc 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -23,22 +23,23 @@
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
+import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
+import static android.os.PowerWhitelistManager.ReasonCode;
+import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
+import static android.os.PowerWhitelistManager.reasonCodeToString;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_COMPANION_APP;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROC_STATE;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_DENIED;
-import static com.android.server.am.ActiveServices.fgsCodeToString;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ProcessRecord.TAG;
@@ -329,7 +330,7 @@
* Does the process has permission to start FGS from background.
*/
@GuardedBy("mService")
- private @ActiveServices.FgsFeatureRetCode int mAllowStartFgsByPermission;
+ private @ReasonCode int mAllowStartFgsByPermission = REASON_DENIED;
/**
* Can this process start FGS from background?
@@ -337,7 +338,7 @@
* another process through service binding.
*/
@GuardedBy("mService")
- private @ActiveServices.FgsFeatureRetCode int mAllowStartFgs;
+ private @ReasonCode int mAllowStartFgs = REASON_DENIED;
/**
* Debugging: primary thing impacting oom_adj.
@@ -1152,44 +1153,47 @@
}
@GuardedBy("mService")
+ int getAllowStartFgsState() {
+ return mAllowStartFgsState;
+ }
+
+ @GuardedBy("mService")
boolean isAllowedStartFgsState() {
return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
}
@GuardedBy("mService")
void setAllowStartFgsByPermission() {
- int ret = FGS_FEATURE_DENIED;
- if (ret == FGS_FEATURE_DENIED) {
- boolean isSystem = false;
- final int uid = UserHandle.getAppId(mApp.info.uid);
- switch (uid) {
- case ROOT_UID:
- case SYSTEM_UID:
- case NFC_UID:
- case SHELL_UID:
- isSystem = true;
- break;
- default:
- isSystem = false;
- break;
- }
-
- if (isSystem) {
- ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
- }
+ int ret = REASON_DENIED;
+ boolean isSystem = false;
+ final int uid = UserHandle.getAppId(mApp.info.uid);
+ switch (uid) {
+ case ROOT_UID:
+ case SYSTEM_UID:
+ case NFC_UID:
+ case SHELL_UID:
+ isSystem = true;
+ break;
+ default:
+ isSystem = false;
+ break;
}
- if (ret == FGS_FEATURE_DENIED) {
+ if (isSystem) {
+ ret = REASON_SYSTEM_UID;
+ }
+
+ if (ret == REASON_DENIED) {
if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
+ ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
} else if (ActivityManager.checkComponentPermission(
START_FOREGROUND_SERVICES_FROM_BACKGROUND,
mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
+ ret = REASON_BACKGROUND_FGS_PERMISSION;
} else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW,
mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
+ ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
}
}
mAllowStartFgs = mAllowStartFgsByPermission = ret;
@@ -1197,59 +1201,65 @@
@GuardedBy("mService")
void setAllowStartFgs() {
- if (mAllowStartFgs != FGS_FEATURE_DENIED) {
+ if (mAllowStartFgs != REASON_DENIED) {
return;
}
- if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+ if (mAllowStartFgs == REASON_DENIED) {
if (isAllowedStartFgsState()) {
- mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+ mAllowStartFgs = getReasonCodeFromProcState(mAllowStartFgsState);
}
}
- if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+ if (mAllowStartFgs == REASON_DENIED) {
// Is the calling UID a device owner app?
if (mService.mInternal != null) {
if (mService.mInternal.isDeviceOwner(mApp.info.uid)) {
- mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
+ mAllowStartFgs = REASON_DEVICE_OWNER;
}
}
}
- if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+ if (mAllowStartFgs == REASON_DENIED) {
if (mService.mInternal != null) {
final boolean isCompanionApp = mService.mInternal.isAssociatedCompanionApp(
UserHandle.getUserId(mApp.info.uid), mApp.info.uid);
if (isCompanionApp) {
- mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_COMPANION_APP;
+ mAllowStartFgs = REASON_COMPANION_DEVICE_MANAGER;
}
}
}
- if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+ if (mAllowStartFgs == REASON_DENIED) {
// Is the calling UID a profile owner app?
if (mService.mInternal != null) {
if (mService.mInternal.isProfileOwner(mApp.info.uid)) {
- mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER;
+ mAllowStartFgs = REASON_PROFILE_OWNER;
}
}
}
- if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+ if (mAllowStartFgs == REASON_DENIED) {
// uid is on DeviceIdleController's user/system allowlist
// or AMS's FgsStartTempAllowList.
- if (mService.isAllowlistedForFgsStartLOSP(mApp.info.uid)) {
- mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
+ FgsStartTempAllowList.TempFgsAllowListEntry entry =
+ mService.isAllowlistedForFgsStartLOSP(mApp.info.uid);
+ if (entry != null) {
+ if (entry == ActivityManagerService.FAKE_TEMP_ALLOWLIST_ENTRY) {
+ mAllowStartFgs = REASON_SYSTEM_ALLOW_LISTED;
+ } else {
+ mAllowStartFgs = entry.mReasonCode;
+ }
}
}
}
@GuardedBy("mService")
- void setAllowStartFgs(@ActiveServices.FgsFeatureRetCode int allowStartFgs) {
+ void setAllowStartFgs(@ReasonCode int allowStartFgs) {
mAllowStartFgs = allowStartFgs;
}
@GuardedBy("mService")
- @ActiveServices.FgsFeatureRetCode int getAllowedStartFgs() {
+ @ReasonCode int getAllowedStartFgs() {
return mAllowStartFgs;
}
@@ -1291,9 +1301,9 @@
pw.println();
pw.print(prefix); pw.print("allowStartFgsState=");
pw.println(mAllowStartFgsState);
- if (mAllowStartFgs != FGS_FEATURE_DENIED) {
+ if (mAllowStartFgs != REASON_DENIED) {
pw.print(prefix); pw.print("allowStartFgs=");
- pw.println(fgsCodeToString(mAllowStartFgs));
+ pw.println(reasonCodeToString(mAllowStartFgs));
}
if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 485087d..3ab95d1 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -18,6 +18,7 @@
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -36,6 +37,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
+import android.os.PowerWhitelistManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -101,7 +103,7 @@
ProcessRecord isolatedProc; // keep track of isolated process, if requested
ServiceState tracker; // tracking service execution, may be null
ServiceState restartTracker; // tracking service restart
- boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
+ boolean allowlistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
boolean delayed; // are we waiting to start this service in the background?
boolean fgRequired; // is the service required to go foreground after starting?
boolean fgWaiting; // is a timeout for going foreground already scheduled?
@@ -156,11 +158,14 @@
// the most recent package that start/bind this service.
String mRecentCallingPackage;
+ // the most recent uid that start/bind this service.
+ int mRecentCallingUid;
// allow the service becomes foreground service? Service started from background may not be
// allowed to become a foreground service.
- @ActiveServices.FgsFeatureRetCode int mAllowStartForeground;
+ @PowerWhitelistManager.ReasonCode int mAllowStartForeground = REASON_DENIED;
String mInfoAllowStartForeground;
+ FgsStartTempAllowList.TempFgsAllowListEntry mInfoTempFgsAllowListReason;
boolean mLoggedInfoAllowStartForeground;
String stringName; // caching of toString
@@ -309,7 +314,7 @@
if (isolatedProc != null) {
isolatedProc.dumpDebug(proto, ServiceRecordProto.ISOLATED_PROC);
}
- proto.write(ServiceRecordProto.WHITELIST_MANAGER, whitelistManager);
+ proto.write(ServiceRecordProto.WHITELIST_MANAGER, allowlistManager);
proto.write(ServiceRecordProto.DELAYED, delayed);
if (isForeground || foregroundId != 0) {
long fgToken = proto.start(ServiceRecordProto.FOREGROUND);
@@ -410,8 +415,8 @@
if (isolatedProc != null) {
pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
}
- if (whitelistManager) {
- pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
+ if (allowlistManager) {
+ pw.print(prefix); pw.print("allowlistManager="); pw.println(allowlistManager);
}
if (mIsAllowedBgActivityStartsByBinding) {
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByBinding=");
@@ -429,6 +434,8 @@
pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("recentCallingPackage=");
pw.println(mRecentCallingPackage);
+ pw.print(prefix); pw.print("recentCallingUid=");
+ pw.println(mRecentCallingUid);
pw.print(prefix); pw.print("allowStartForeground=");
pw.println(mAllowStartForeground);
pw.print(prefix); pw.print("infoAllowStartForeground=");
@@ -894,13 +901,13 @@
return false;
}
- public void updateWhitelistManager() {
- whitelistManager = false;
+ public void updateAllowlistManager() {
+ allowlistManager = false;
for (int conni=connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
for (int i=0; i<cr.size(); i++) {
if ((cr.get(i).flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
- whitelistManager = true;
+ allowlistManager = true;
return;
}
}
diff --git a/services/core/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
index 4cc1fc1..9dddd65 100644
--- a/services/core/java/com/android/server/am/StrictModeViolationDialog.java
+++ b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
@@ -82,6 +82,11 @@
DISMISS_TIMEOUT);
}
+ @Override
+ protected void closeDialog() {
+ mHandler.obtainMessage(ACTION_OK).sendToTarget();
+ }
+
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
synchronized (mService.mProcLock) {
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 4061df4..03eddc9 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -44,6 +44,23 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "file_patterns": ["Battery[^/]*\\.java", "MeasuredEnergy[^/]*\\.java"],
+ "name": "FrameworksCoreTests",
+ "options": [
+ { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+ { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+ ]
+ },
+ {
+ "file_patterns": ["Battery[^/]*\\.java", "MeasuredEnergy[^/]*\\.java"],
+ "name": "FrameworksServicesTests",
+ "options": [
+ { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+ { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+ { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+ ]
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6dd78e7..caf2510 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -27,6 +27,9 @@
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
@@ -74,6 +77,7 @@
import android.os.IUserManager;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerWhitelistManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -522,7 +526,8 @@
mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
AppOpsManager.OP_NONE,
- getTemporaryAppWhitelistBroadcastOptions().toBundle(), true,
+ getTemporaryAppAllowlistBroadcastOptions(REASON_LOCKED_BOOT_COMPLETED)
+ .toBundle(), true,
false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(), userId);
}
@@ -770,9 +775,8 @@
}, 0, null, null,
new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
AppOpsManager.OP_NONE,
- getTemporaryAppWhitelistBroadcastOptions().toBundle(), true,
- false, MY_PID, SYSTEM_UID,
- callingUid, callingPid, userId);
+ getTemporaryAppAllowlistBroadcastOptions(REASON_BOOT_COMPLETED).toBundle(),
+ true, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
});
}
@@ -2811,7 +2815,8 @@
}
}
- private BroadcastOptions getTemporaryAppWhitelistBroadcastOptions() {
+ private BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+ @PowerWhitelistManager.ReasonCode int reasonCode) {
long duration = 10_000;
final ActivityManagerInternal amInternal =
LocalServices.getService(ActivityManagerInternal.class);
@@ -2819,9 +2824,8 @@
duration = amInternal.getBootTimeTempAllowListDuration();
}
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
- bOptions.setTemporaryAppWhitelistDuration(
- BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- duration);
+ bOptions.setTemporaryAppAllowlist(duration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, reasonCode, "");
return bOptions;
}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 33bdac2..32ae878 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -57,10 +57,13 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -511,6 +514,37 @@
return mIsServiceEnabled;
}
+ private void dump(PrintWriter pw) {
+ // Check usage stats permission since hibernation indirectly informs usage.
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
+
+ IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
+
+ synchronized (mLock) {
+ final int userCount = mUserStates.size();
+ for (int i = 0; i < userCount; i++) {
+ final int userId = mUserStates.keyAt(i);
+ idpw.print("User Level Hibernation States, ");
+ idpw.printPair("user", userId);
+ idpw.println();
+ Map<String, UserLevelState> stateMap = mUserStates.get(i);
+ idpw.increaseIndent();
+ for (UserLevelState state : stateMap.values()) {
+ idpw.print(state);
+ idpw.println();
+ }
+ idpw.decreaseIndent();
+ }
+ idpw.println();
+ idpw.print("Global Level Hibernation States");
+ idpw.println();
+ for (GlobalLevelState state : mGlobalHibernationStates.values()) {
+ idpw.print(state);
+ idpw.println();
+ }
+ }
+ }
+
private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
@@ -547,6 +581,12 @@
new AppHibernationShellCommand(mService).exec(this, in, out, err, args, callback,
resultReceiver);
}
+
+ @Override
+ protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
+ @Nullable String[] args) {
+ mService.dump(fout);
+ }
}
// Broadcast receiver for package add/removal events
diff --git a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
index 4f75675..baa84b7 100644
--- a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
@@ -22,4 +22,12 @@
final class GlobalLevelState {
public String packageName;
public boolean hibernated;
+
+ @Override
+ public String toString() {
+ return "GlobalLevelState{"
+ + "packageName='" + packageName + '\''
+ + ", hibernated=" + hibernated
+ + '}';
+ }
}
diff --git a/services/core/java/com/android/server/apphibernation/UserLevelState.java b/services/core/java/com/android/server/apphibernation/UserLevelState.java
index c66dad8..272d3d1 100644
--- a/services/core/java/com/android/server/apphibernation/UserLevelState.java
+++ b/services/core/java/com/android/server/apphibernation/UserLevelState.java
@@ -22,4 +22,12 @@
final class UserLevelState {
public String packageName;
public boolean hibernated;
+
+ @Override
+ public String toString() {
+ return "UserLevelState{"
+ + "packageName='" + packageName + '\''
+ + ", hibernated=" + hibernated
+ + '}';
+ }
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a776458..44dcc20 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -339,7 +339,10 @@
SparseIntArray mProfileOwners;
@GuardedBy("this")
- private CheckOpsDelegate mCheckOpsDelegate;
+ private CheckOpsDelegate mAppOpsPolicy;
+
+ @GuardedBy("this")
+ private CheckOpsDelegateDispatcher mCheckOpsDelegateDispatcher;
/**
* Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never
@@ -1770,6 +1773,17 @@
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
}
+ /**
+ * Sets a policy for handling app ops.
+ *
+ * @param appOpsPolicy The policy.
+ */
+ public void setAppOpsPolicy(@Nullable CheckOpsDelegate appOpsPolicy) {
+ synchronized (AppOpsService.this) {
+ mAppOpsPolicy = appOpsPolicy;
+ }
+ }
+
public void packageRemoved(int uid, String packageName) {
synchronized (this) {
UidState uidState = mUidStates.get(uid);
@@ -2868,13 +2882,19 @@
public CheckOpsDelegate getAppOpsServiceDelegate() {
synchronized (this) {
- return mCheckOpsDelegate;
+ return (mCheckOpsDelegateDispatcher != null)
+ ? mCheckOpsDelegateDispatcher.getCheckOpsDelegate()
+ : null;
}
}
public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
synchronized (this) {
- mCheckOpsDelegate = delegate;
+ if (delegate != null) {
+ mCheckOpsDelegateDispatcher = new CheckOpsDelegateDispatcher(delegate);
+ } else {
+ mCheckOpsDelegateDispatcher = null;
+ }
}
}
@@ -2889,19 +2909,28 @@
}
private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
- final CheckOpsDelegate delegate;
- synchronized (this) {
- delegate = mCheckOpsDelegate;
+ final CheckOpsDelegate policy;
+ final CheckOpsDelegateDispatcher delegateDispatcher;
+ synchronized (AppOpsService.this) {
+ policy = mAppOpsPolicy;
+ delegateDispatcher = mCheckOpsDelegateDispatcher;
}
- if (delegate == null) {
- return checkOperationImpl(code, uid, packageName, raw);
+ if (policy != null) {
+ if (delegateDispatcher != null) {
+ return policy.checkOperation(code, uid, packageName, raw,
+ delegateDispatcher::checkOperationImpl);
+ } else {
+ return policy.checkOperation(code, uid, packageName, raw,
+ AppOpsService.this::checkOperationImpl);
+ }
+ } else if (delegateDispatcher != null) {
+ delegateDispatcher.getCheckOpsDelegate().checkOperation(code, uid,
+ packageName, raw, AppOpsService.this::checkOperationImpl);
}
- return delegate.checkOperation(code, uid, packageName, raw,
- AppOpsService.this::checkOperationImpl);
+ return checkOperationImpl(code, uid, packageName, raw);
}
- private int checkOperationImpl(int code, int uid, String packageName,
- boolean raw) {
+ private int checkOperationImpl(int code, int uid, String packageName, boolean raw) {
verifyIncomingOp(code);
verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
@@ -2956,15 +2985,25 @@
@Override
public int checkAudioOperation(int code, int usage, int uid, String packageName) {
- final CheckOpsDelegate delegate;
- synchronized (this) {
- delegate = mCheckOpsDelegate;
+ final CheckOpsDelegate policy;
+ final CheckOpsDelegateDispatcher delegateDispatcher;
+ synchronized (AppOpsService.this) {
+ policy = mAppOpsPolicy;
+ delegateDispatcher = mCheckOpsDelegateDispatcher;
}
- if (delegate == null) {
- return checkAudioOperationImpl(code, usage, uid, packageName);
+ if (policy != null) {
+ if (delegateDispatcher != null) {
+ return policy.checkAudioOperation(code, usage, uid, packageName,
+ delegateDispatcher::checkAudioOperationImpl);
+ } else {
+ return policy.checkAudioOperation(code, usage, uid, packageName,
+ AppOpsService.this::checkAudioOperationImpl);
+ }
+ } else if (delegateDispatcher != null) {
+ delegateDispatcher.getCheckOpsDelegate().checkAudioOperation(code, usage,
+ uid, packageName, AppOpsService.this::checkAudioOperationImpl);
}
- return delegate.checkAudioOperation(code, usage, uid, packageName,
- AppOpsService.this::checkAudioOperationImpl);
+ return checkAudioOperationImpl(code, usage, uid, packageName);
}
private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
@@ -3078,17 +3117,29 @@
@Override
public int noteOperation(int code, int uid, String packageName, String attributionTag,
boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage) {
- final CheckOpsDelegate delegate;
- synchronized (this) {
- delegate = mCheckOpsDelegate;
+ final CheckOpsDelegate policy;
+ final CheckOpsDelegateDispatcher delegateDispatcher;
+ synchronized (AppOpsService.this) {
+ policy = mAppOpsPolicy;
+ delegateDispatcher = mCheckOpsDelegateDispatcher;
}
- if (delegate == null) {
- return noteOperationImpl(code, uid, packageName, attributionTag,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ if (policy != null) {
+ if (delegateDispatcher != null) {
+ return policy.noteOperation(code, uid, packageName, attributionTag,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ delegateDispatcher::noteOperationImpl);
+ } else {
+ return policy.noteOperation(code, uid, packageName, attributionTag,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ AppOpsService.this::noteOperationImpl);
+ }
+ } else if (delegateDispatcher != null) {
+ delegateDispatcher.getCheckOpsDelegate().noteOperation(code, uid, packageName,
+ attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ AppOpsService.this::noteOperationImpl);
}
- return delegate.noteOperation(code, uid, packageName, attributionTag,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- AppOpsService.this::noteOperationImpl);
+ return noteOperationImpl(code, uid, packageName, attributionTag,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage);
}
private int noteOperationImpl(int code, int uid, @Nullable String packageName,
@@ -6589,7 +6640,6 @@
}
}
-
/**
* Async task for writing note op stack trace, op code, package name and version to file
* More specifically, writes all the collected ops from {@link #mNoteOpCallerStacktraces}
@@ -6726,4 +6776,34 @@
}
}
}
+
+ private final class CheckOpsDelegateDispatcher {
+ private final @NonNull CheckOpsDelegate mCheckOpsDelegate;
+
+ CheckOpsDelegateDispatcher(@NonNull CheckOpsDelegate checkOpsDelegate) {
+ mCheckOpsDelegate = checkOpsDelegate;
+ }
+
+ public @NonNull CheckOpsDelegate getCheckOpsDelegate() {
+ return mCheckOpsDelegate;
+ }
+
+ public int checkOperationImpl(int code, int uid, String packageName, boolean raw) {
+ return mCheckOpsDelegate.checkOperation(code, uid, packageName, raw,
+ AppOpsService.this::checkOperationImpl);
+ }
+
+ public int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
+ return mCheckOpsDelegate.checkAudioOperation(code, usage, uid, packageName,
+ AppOpsService.this::checkAudioOperationImpl);
+ }
+
+ public int noteOperationImpl(int code, int uid, @Nullable String packageName,
+ @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message, boolean shouldCollectMessage) {
+ return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ AppOpsService.this::noteOperationImpl);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 322c210..42fcd44 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -246,8 +246,8 @@
ClipData primaryClip;
/** UID that set {@link #primaryClip}. */
int primaryClipUid = android.os.Process.NOBODY_UID;
- /** Application label of the app that set {@link #primaryClip}. */
- CharSequence mPrimaryClipAppLabel;
+ /** Package of the app that set {@link #primaryClip}. */
+ String mPrimaryClipPackage;
final HashSet<String> activePermissionOwners
= new HashSet<String>();
@@ -528,20 +528,9 @@
}
}
- // Retrieve the app label of the source of the clip data
- CharSequence sourceAppLabel = null;
- if (clip != null && sourcePackage != null) {
- try {
- sourceAppLabel =
- mPm.getApplicationLabel(mPm.getApplicationInfo(sourcePackage, 0));
- } catch (PackageManager.NameNotFoundException e) {
- // leave label as null
- }
- }
-
// Update this user
final int userId = UserHandle.getUserId(uid);
- setPrimaryClipInternal(getClipboard(userId), clip, uid, sourceAppLabel);
+ setPrimaryClipInternal(getClipboard(userId), clip, uid, sourcePackage);
// Update related users
List<UserInfo> related = getRelatedProfiles(userId);
@@ -576,7 +565,7 @@
UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
if (canCopyIntoProfile) {
setPrimaryClipInternal(
- getClipboard(id), clip, uid, sourceAppLabel);
+ getClipboard(id), clip, uid, sourcePackage);
}
}
}
@@ -590,7 +579,7 @@
}
private void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
- int uid, @Nullable CharSequence sourceAppLabel) {
+ int uid, @Nullable String sourcePackage) {
revokeUris(clipboard);
clipboard.activePermissionOwners.clear();
if (clip == null && clipboard.primaryClip == null) {
@@ -599,10 +588,10 @@
clipboard.primaryClip = clip;
if (clip != null) {
clipboard.primaryClipUid = uid;
- clipboard.mPrimaryClipAppLabel = sourceAppLabel;
+ clipboard.mPrimaryClipPackage = sourcePackage;
} else {
clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
- clipboard.mPrimaryClipAppLabel = null;
+ clipboard.mPrimaryClipPackage = null;
}
if (clip != null) {
final ClipDescription description = clip.getDescription();
@@ -887,12 +876,23 @@
return;
}
+ // Retrieve the app label of the source of the clip data
+ CharSequence sourceAppLabel = null;
+ if (clipboard.mPrimaryClipPackage != null) {
+ try {
+ sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
+ clipboard.mPrimaryClipPackage, 0, userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ // leave label as null
+ }
+ }
+
try {
CharSequence callingAppLabel = mPm.getApplicationLabel(
- mPm.getApplicationInfo(callingPackage, 0));
+ mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
String message;
- if (clipboard.mPrimaryClipAppLabel != null) {
- message = callingAppLabel + " pasted from " + clipboard.mPrimaryClipAppLabel;
+ if (sourceAppLabel != null) {
+ message = callingAppLabel + " pasted from " + sourceAppLabel;
} else {
message = callingAppLabel + " pasted from clipboard";
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 422991e..66a6520 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -50,6 +50,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -595,17 +596,23 @@
* Rechecks all the existing overrides for a package.
*/
void recheckOverrides(String packageName) {
+ // Local cache of compat changes. Holding a lock on mChanges for the whole duration of the
+ // method will cause a deadlock.
+ List<CompatChange> changes;
synchronized (mChanges) {
- boolean shouldInvalidateCache = false;
+ changes = new ArrayList<>(mChanges.size());
for (int idx = 0; idx < mChanges.size(); ++idx) {
- CompatChange c = mChanges.valueAt(idx);
- OverrideAllowedState allowedState =
- mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
- shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
+ changes.add(mChanges.valueAt(idx));
}
- if (shouldInvalidateCache) {
- invalidateCache();
- }
+ }
+ boolean shouldInvalidateCache = false;
+ for (CompatChange c: changes) {
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
+ shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
+ }
+ if (shouldInvalidateCache) {
+ invalidateCache();
}
}
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 21ef356..4ecc759 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -26,6 +26,7 @@
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -226,7 +227,7 @@
mNetworkTemplate = new NetworkTemplate(
NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL);
+ NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
mUsageCallback = new UsageCallback() {
@Override
public void onThresholdReached(int networkType, String subscriberId) {
@@ -274,7 +275,8 @@
null /* networkId, unused for matching mobile networks */,
!nc.hasCapability(NET_CAPABILITY_NOT_ROAMING),
!nc.hasCapability(NET_CAPABILITY_NOT_METERED),
- false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */);
+ false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */,
+ OEM_MANAGED_ALL);
}
private long getRemainingDailyBudget(long limitBytes,
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 01ac81fb..67f495a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,6 +22,7 @@
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+import static android.os.PowerWhitelistManager.REASON_VPN;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -825,7 +826,8 @@
// a short time, so we can bootstrap the VPN service.
DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal();
idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
- VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, "vpn");
+ VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN,
+ "vpn");
// Start the VPN service declared in the app's manifest.
Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 7b9ca37..ae0e001 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,8 @@
package com.android.server.content;
+import static android.os.PowerWhitelistManager.REASON_SYNC_MANAGER;
+
import static com.android.server.content.SyncLogger.logSafe;
import android.accounts.Account;
@@ -1671,7 +1673,7 @@
syncOperation.owningPackage,
mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
UserHandle.getUserId(syncOperation.owningUid),
- /* sync=*/ false, "sync by top app");
+ /* sync=*/ false, REASON_SYNC_MANAGER, "sync by top app");
}
}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index b3a6f26..835b468 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.IDeviceStateManager;
import android.hardware.devicestate.IDeviceStateManagerCallback;
@@ -47,6 +48,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Optional;
/**
@@ -76,6 +78,9 @@
public final class DeviceStateManagerService extends SystemService {
private static final String TAG = "DeviceStateManagerService";
private static final boolean DEBUG = false;
+ // The device state to use as a placeholder before callback from the DeviceStateProvider occurs.
+ private static final DeviceState UNSPECIFIED_DEVICE_STATE =
+ new DeviceState(MINIMUM_DEVICE_STATE, "UNSPECIFIED");
private final Object mLock = new Object();
@NonNull
@@ -87,11 +92,11 @@
@GuardedBy("mLock")
private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();
- // The current committed device state. The default of UNSET will be replaced by
- // the current state after the initial callback from the DeviceStateProvider.
+ // The current committed device state. The default of UNSPECIFIED_DEVICE_STATE will be replaced
+ // by the current state after the initial callback from the DeviceStateProvider.
@GuardedBy("mLock")
@NonNull
- private DeviceState mCommittedState = new DeviceState(MINIMUM_DEVICE_STATE, "UNSET");
+ private DeviceState mCommittedState = UNSPECIFIED_DEVICE_STATE;
// The device state that is currently awaiting callback from the policy to be committed.
@GuardedBy("mLock")
@NonNull
@@ -103,7 +108,7 @@
// The device state that is set by the device state provider.
@GuardedBy("mLock")
@NonNull
- private Optional<DeviceState> mBaseState = Optional.empty();
+ private DeviceState mBaseState = UNSPECIFIED_DEVICE_STATE;
// List of processes registered to receive notifications about changes to device state and
// request status indexed by process id.
@@ -166,7 +171,7 @@
* @see #getOverrideState()
*/
@NonNull
- Optional<DeviceState> getBaseState() {
+ DeviceState getBaseState() {
synchronized (mLock) {
return mBaseState;
}
@@ -203,33 +208,47 @@
/** Returns the list of currently supported device state identifiers. */
private int[] getSupportedStateIdentifiers() {
synchronized (mLock) {
- int[] supportedStates = new int[mDeviceStates.size()];
- for (int i = 0; i < supportedStates.length; i++) {
- supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
- }
- return supportedStates;
+ return getSupportedStateIdentifiersLocked();
}
}
+ /** Returns the list of currently supported device state identifiers. */
+ private int[] getSupportedStateIdentifiersLocked() {
+ int[] supportedStates = new int[mDeviceStates.size()];
+ for (int i = 0; i < supportedStates.length; i++) {
+ supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
+ }
+ return supportedStates;
+ }
+
+ @NonNull
+ private DeviceStateInfo getDeviceStateInfoLocked() {
+ final int[] supportedStates = getSupportedStateIdentifiersLocked();
+ final int baseState = mBaseState.getIdentifier();
+ final int currentState = mCommittedState.getIdentifier();
+
+ return new DeviceStateInfo(supportedStates, baseState, currentState);
+ }
+
@VisibleForTesting
IDeviceStateManager getBinderService() {
return mBinderService;
}
private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
+ boolean updatedPendingState;
synchronized (mLock) {
+ final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();
+
mDeviceStates.clear();
for (int i = 0; i < supportedDeviceStates.length; i++) {
DeviceState state = supportedDeviceStates[i];
mDeviceStates.put(state.getIdentifier(), state);
}
- if (mBaseState.isPresent()
- && !isSupportedStateLocked(mBaseState.get().getIdentifier())) {
- // The current base state is no longer valid. We'll clear it here, though
- // we won't actually update the current state until a callback comes from the
- // provider with the most recent state.
- mBaseState = Optional.empty();
+ final int[] newStateIdentifiers = getSupportedStateIdentifiersLocked();
+ if (Arrays.equals(oldStateIdentifiers, newStateIdentifiers)) {
+ return;
}
final int requestSize = mRequestRecords.size();
@@ -240,7 +259,14 @@
}
}
- updatePendingStateLocked();
+ updatedPendingState = updatePendingStateLocked();
+ }
+
+ if (!updatedPendingState) {
+ // If the change in the supported states didn't result in a change of the pending state
+ // commitPendingState() will never be called and the callbacks will never be notified
+ // of the change.
+ notifyDeviceStateInfoChanged();
}
notifyRequestsOfStatusChangeIfNeeded();
@@ -265,23 +291,25 @@
}
/**
- * Requests to set the base state. The request may not be honored under certain conditions, for
- * example if the provided state is not supported.
+ * Sets the base state.
+ *
+ * @throws IllegalArgumentException if the {@code identifier} is not a supported state.
*
* @see #isSupportedStateLocked(int)
*/
private void setBaseState(int identifier) {
+ boolean updatedPendingState;
synchronized (mLock) {
- if (mBaseState.isPresent() && mBaseState.get().getIdentifier() == identifier) {
- // Base state hasn't changed. Nothing to do.
- return;
- }
-
- final Optional<DeviceState> baseState = getStateLocked(identifier);
- if (!baseState.isPresent()) {
+ final Optional<DeviceState> baseStateOptional = getStateLocked(identifier);
+ if (!baseStateOptional.isPresent()) {
throw new IllegalArgumentException("Base state is not supported");
}
+ final DeviceState baseState = baseStateOptional.get();
+ if (mBaseState.equals(baseState)) {
+ // Base state hasn't changed. Nothing to do.
+ return;
+ }
mBaseState = baseState;
final int requestSize = mRequestRecords.size();
@@ -292,7 +320,14 @@
}
}
- updatePendingStateLocked();
+ updatedPendingState = updatePendingStateLocked();
+ }
+
+ if (!updatedPendingState) {
+ // If the change in base state didn't result in a change of the pending state
+ // commitPendingState() will never be called and the callbacks will never be notified
+ // of the change.
+ notifyDeviceStateInfoChanged();
}
notifyRequestsOfStatusChangeIfNeeded();
@@ -303,32 +338,39 @@
* Tries to update the current pending state with the current requested state. Must call
* {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being
* changed.
+ *
+ * @return {@code true} if the pending state has changed as a result of this call, {@code false}
+ * otherwise.
*/
- private void updatePendingStateLocked() {
+ private boolean updatePendingStateLocked() {
if (mPendingState.isPresent()) {
// Have pending state, can not configure a new state until the state is committed.
- return;
+ return false;
}
final DeviceState stateToConfigure;
if (!mRequestRecords.isEmpty()) {
stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
+ } else if (isSupportedStateLocked(mBaseState.getIdentifier())) {
+ // Base state could have recently become unsupported after a change in supported states.
+ stateToConfigure = mBaseState;
} else {
- stateToConfigure = mBaseState.orElse(null);
+ stateToConfigure = null;
}
if (stateToConfigure == null) {
// No currently requested state.
- return;
+ return false;
}
- if (stateToConfigure == mCommittedState) {
+ if (stateToConfigure.equals(mCommittedState)) {
// The state requesting to be committed already matches the current committed state.
- return;
+ return false;
}
mPendingState = Optional.of(stateToConfigure);
mIsPolicyWaitingForState = true;
+ return true;
}
/**
@@ -374,13 +416,11 @@
*/
private void commitPendingState() {
// Update the current state.
- int newState;
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "Committing state: " + mPendingState);
}
mCommittedState = mPendingState.get();
- newState = mCommittedState.getIdentifier();
if (!mRequestRecords.isEmpty()) {
final OverrideRequestRecord topRequest =
@@ -393,7 +433,7 @@
}
// Notify callbacks of a change.
- notifyDeviceStateChanged(newState);
+ notifyDeviceStateInfoChanged();
// Notify the top request that it's active.
notifyRequestsOfStatusChangeIfNeeded();
@@ -402,14 +442,15 @@
notifyPolicyIfNeeded();
}
- private void notifyDeviceStateChanged(int deviceState) {
+ private void notifyDeviceStateInfoChanged() {
if (Thread.holdsLock(mLock)) {
throw new IllegalStateException(
"Attempting to notify callbacks with service lock held.");
}
- // Grab the lock and copy the process records.
+ // Grab the lock and copy the process records and the current info.
ArrayList<ProcessRecord> registeredProcesses;
+ DeviceStateInfo info;
synchronized (mLock) {
if (mProcessRecords.size() == 0) {
return;
@@ -419,11 +460,13 @@
for (int i = 0; i < mProcessRecords.size(); i++) {
registeredProcesses.add(mProcessRecords.valueAt(i));
}
+
+ info = getDeviceStateInfoLocked();
}
// After releasing the lock, send the notifications out.
for (int i = 0; i < registeredProcesses.size(); i++) {
- registeredProcesses.get(i).notifyDeviceStateAsync(deviceState);
+ registeredProcesses.get(i).notifyDeviceStateInfoAsync(info);
}
}
@@ -454,28 +497,20 @@
}
private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
- int currentState;
- ProcessRecord record;
- // Grab the lock to register the callback and get the current state.
synchronized (mLock) {
if (mProcessRecords.contains(pid)) {
throw new SecurityException("The calling process has already registered an"
+ " IDeviceStateManagerCallback.");
}
- record = new ProcessRecord(callback, pid);
+ ProcessRecord record = new ProcessRecord(callback, pid);
try {
callback.asBinder().linkToDeath(record, 0);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
-
mProcessRecords.put(pid, record);
- currentState = mCommittedState.getIdentifier();
}
-
- // Notify the callback of the state at registration.
- record.notifyDeviceStateAsync(currentState);
}
private void handleProcessDied(ProcessRecord processRecord) {
@@ -626,9 +661,9 @@
handleProcessDied(this);
}
- public void notifyDeviceStateAsync(int devicestate) {
+ public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) {
try {
- mCallback.onDeviceStateChanged(devicestate);
+ mCallback.onDeviceStateInfoChanged(info);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.",
ex);
@@ -752,6 +787,13 @@
/** Implementation of {@link IDeviceStateManager} published as a binder service. */
private final class BinderService extends IDeviceStateManager.Stub {
@Override // Binder call
+ public DeviceStateInfo getDeviceStateInfo() {
+ synchronized (mLock) {
+ return getDeviceStateInfoLocked();
+ }
+ }
+
+ @Override // Binder call
public void registerCallback(IDeviceStateManagerCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("Device state callback must not be null.");
@@ -767,16 +809,6 @@
}
@Override // Binder call
- public int[] getSupportedDeviceStates() {
- final long token = Binder.clearCallingIdentity();
- try {
- return getSupportedStateIdentifiers();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override // Binder call
public void requestState(IBinder token, int state, int flags) {
getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
"Permission required to request device state.");
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index 6cc55a6..f346600 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -64,13 +64,13 @@
private void printState(PrintWriter pw) {
DeviceState committedState = mService.getCommittedState();
- Optional<DeviceState> baseState = mService.getBaseState();
+ DeviceState baseState = mService.getBaseState();
Optional<DeviceState> overrideState = mService.getOverrideState();
pw.println("Committed state: " + committedState);
if (overrideState.isPresent()) {
pw.println("----------------------");
- pw.println("Base state: " + baseState.orElse(null));
+ pw.println("Base state: " + baseState);
pw.println("Override state: " + overrideState.get());
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c62dd72..52149ee 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -532,7 +532,7 @@
DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class);
- deviceStateManager.addDeviceStateListener(new HandlerExecutor(mHandler),
+ deviceStateManager.registerCallback(new HandlerExecutor(mHandler),
new DeviceStateListener());
scheduleTraversalLocked(false);
@@ -2974,9 +2974,9 @@
/**
* Listens to changes in device state and reports the state to LogicalDisplayMapper.
*/
- class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+ class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
@Override
- public void onDeviceStateChanged(int deviceState) {
+ public void onStateChanged(int deviceState) {
synchronized (mSyncRoot) {
mLogicalDisplayMapper.setDeviceStateLocked(deviceState);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2005a74..0117326 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -469,18 +469,10 @@
DisplayDeviceConfig displayDeviceConfig = logicalDisplay
.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
- // TODO: (b/178183143) Ensure that the ddc is not null
- if (displayDeviceConfig != null) {
- mBrightnessRampRateFastDecrease = displayDeviceConfig.getBrightnessRampFastDecrease();
- mBrightnessRampRateFastIncrease = displayDeviceConfig.getBrightnessRampFastIncrease();
- mBrightnessRampRateSlowDecrease = displayDeviceConfig.getBrightnessRampSlowDecrease();
- mBrightnessRampRateSlowIncrease = displayDeviceConfig.getBrightnessRampSlowIncrease();
- } else {
- mBrightnessRampRateFastDecrease = 1.0f;
- mBrightnessRampRateFastIncrease = 1.0f;
- mBrightnessRampRateSlowDecrease = 1.0f;
- mBrightnessRampRateSlowIncrease = 1.0f;
- }
+ mBrightnessRampRateFastDecrease = displayDeviceConfig.getBrightnessRampFastDecrease();
+ mBrightnessRampRateFastIncrease = displayDeviceConfig.getBrightnessRampFastIncrease();
+ mBrightnessRampRateSlowDecrease = displayDeviceConfig.getBrightnessRampSlowDecrease();
+ mBrightnessRampRateSlowIncrease = displayDeviceConfig.getBrightnessRampSlowIncrease();
mSkipScreenOnBrightnessRamp = resources.getBoolean(
com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
@@ -866,8 +858,10 @@
private void cleanupHandlerThreadAfterStop() {
setProximitySensorEnabled(false);
mHandler.removeCallbacksAndMessages(null);
- mPowerState.stop();
- mPowerState = null;
+ if (mPowerState != null) {
+ mPowerState.stop();
+ mPowerState = null;
+ }
}
private void updatePowerState() {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 48f335d..3709963 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -638,11 +638,7 @@
mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
- if (mDisplayDeviceConfig != null) {
- mInfo.brightnessDefault = mDisplayDeviceConfig.getBrightnessDefault();
- } else {
- mInfo.brightnessDefault = 0.5f;
- }
+ mInfo.brightnessDefault = getDisplayDeviceConfig().getBrightnessDefault();
}
return mInfo;
}
diff --git a/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java b/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
index d514aab..62337c7 100644
--- a/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
+++ b/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
@@ -46,7 +46,7 @@
private static final String ATTR_VALUE = "value";
/* package */ static class Config {
- public long lastModifiedDate;
+ public long lastModifiedMillis;
public final Set<String> updatedFontDirs = new ArraySet<>();
public final List<FontConfig.FontFamily> fontFamilies = new ArrayList<>();
}
@@ -73,7 +73,7 @@
} else if (depth == 2) {
switch (tag) {
case TAG_LAST_MODIFIED_DATE:
- out.lastModifiedDate = parseLongAttribute(parser, ATTR_VALUE, 0);
+ out.lastModifiedMillis = parseLongAttribute(parser, ATTR_VALUE, 0);
break;
case TAG_UPDATED_FONT_DIR:
out.updatedFontDirs.add(getAttribute(parser, ATTR_VALUE));
@@ -101,7 +101,7 @@
out.startTag(null, TAG_ROOT);
out.startTag(null, TAG_LAST_MODIFIED_DATE);
- out.attribute(null, ATTR_VALUE, Long.toString(config.lastModifiedDate));
+ out.attribute(null, ATTR_VALUE, Long.toString(config.lastModifiedMillis));
out.endTag(null, TAG_LAST_MODIFIED_DATE);
for (String dir : config.updatedFontDirs) {
out.startTag(null, TAG_UPDATED_FONT_DIR);
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 08ddc6d..86dbe86 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -112,7 +112,7 @@
private final File mConfigFile;
private final File mTmpConfigFile;
- private long mLastModifiedDate;
+ private long mLastModifiedMillis;
private int mConfigVersion = 1;
/**
@@ -147,7 +147,7 @@
/* package */ void loadFontFileMap() {
mFontFileInfoMap.clear();
mFontFamilyMap.clear();
- mLastModifiedDate = 0;
+ mLastModifiedMillis = 0;
boolean success = false;
try {
PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
@@ -157,7 +157,7 @@
Slog.e(TAG, "Failed to load config xml file", e);
return;
}
- mLastModifiedDate = config.lastModifiedDate;
+ mLastModifiedMillis = config.lastModifiedMillis;
File[] dirs = mFilesDir.listFiles();
if (dirs == null) return;
@@ -200,7 +200,7 @@
if (!success) {
mFontFileInfoMap.clear();
mFontFamilyMap.clear();
- mLastModifiedDate = 0;
+ mLastModifiedMillis = 0;
FileUtils.deleteContents(mFilesDir);
}
}
@@ -211,7 +211,7 @@
FileUtils.deleteContents(mFilesDir);
mFontFamilyMap.clear();
- mLastModifiedDate = Instant.now().getEpochSecond();
+ mLastModifiedMillis = System.currentTimeMillis();
try (FileOutputStream fos = new FileOutputStream(mConfigFile)) {
PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig());
} catch (Exception e) {
@@ -231,7 +231,7 @@
// Backup the mapping for rollback.
ArrayMap<String, FontFileInfo> backupMap = new ArrayMap<>(mFontFileInfoMap);
ArrayMap<String, FontConfig.FontFamily> backupFamilies = new ArrayMap<>(mFontFamilyMap);
- long backupLastModifiedDate = mLastModifiedDate;
+ long backupLastModifiedDate = mLastModifiedMillis;
boolean success = false;
try {
for (FontUpdateRequest request : requests) {
@@ -247,7 +247,7 @@
}
// Write config file.
- mLastModifiedDate = Instant.now().getEpochSecond();
+ mLastModifiedMillis = Instant.now().getEpochSecond();
try (FileOutputStream fos = new FileOutputStream(mTmpConfigFile)) {
PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig());
} catch (Exception e) {
@@ -269,7 +269,7 @@
mFontFileInfoMap.putAll(backupMap);
mFontFamilyMap.clear();
mFontFamilyMap.putAll(backupFamilies);
- mLastModifiedDate = backupLastModifiedDate;
+ mLastModifiedMillis = backupLastModifiedDate;
}
}
}
@@ -527,7 +527,7 @@
private PersistentSystemFontConfig.Config createPersistentConfig() {
PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
- config.lastModifiedDate = mLastModifiedDate;
+ config.lastModifiedMillis = mLastModifiedMillis;
for (FontFileInfo info : mFontFileInfoMap.values()) {
config.updatedFontDirs.add(info.getRandomizedFontDir().getName());
}
@@ -560,7 +560,7 @@
// which will be used as a fallback font without being overridden.
mergedFamilies.addAll(mFontFamilyMap.values());
return new FontConfig(
- mergedFamilies, config.getAliases(), mLastModifiedDate, mConfigVersion);
+ mergedFamilies, config.getAliases(), mLastModifiedMillis, mConfigVersion);
}
/* package */ int getConfigVersion() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b4d9b01..115cafed 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -221,7 +221,7 @@
private int mHdmiCecVolumeControl;
// Make sure HdmiCecConfig is instantiated and the XMLs are read.
- private final HdmiCecConfig mHdmiCecConfig;
+ private HdmiCecConfig mHdmiCecConfig;
/**
* Interface to report send result.
@@ -580,6 +580,11 @@
mHdmiCecNetwork = hdmiCecNetwork;
}
+ @VisibleForTesting
+ void setHdmiCecConfig(HdmiCecConfig hdmiCecConfig) {
+ mHdmiCecConfig = hdmiCecConfig;
+ }
+
public HdmiCecNetwork getHdmiCecNetwork() {
return mHdmiCecNetwork;
}
diff --git a/services/core/java/com/android/server/hdmi/cec_key_handling.md b/services/core/java/com/android/server/hdmi/cec_key_handling.md
index 1b41a67..69877be 100644
--- a/services/core/java/com/android/server/hdmi/cec_key_handling.md
+++ b/services/core/java/com/android/server/hdmi/cec_key_handling.md
@@ -1,36 +1,37 @@
# CEC Key Handling
-The mapping of CEC key codes to Android key codes are at
-[HdmiCecKeycode](HdmiCecKeycode.java)
+The mapping of CEC keycodes to Android keycodes is done at [HdmiCecKeycode](HdmiCecKeycode.java).
# Android TV
-Android TV requires special handling of some keys.
+Android TV (ATV) requires special handling of some keys.
-The general action for key handling is described in the table
+The general action for key handling is described in the table below.
| Android Key | TV Panel | OTT | Soundbar |
| ----------- | ----------------- | ------------------- | ------------------- |
-| general | Send to active source | handle on device | handle on device |
| POWER | Toggle the device power state | Toggle the OTT power state, TV power state follows | Toggle the soundbar power state, TV power state follows|
| TV_POWER | Toggle the device power state | Toggle the TV power state, OTT power state follows | Toggle the TV power state, soundbar power state follows|
| HOME | Turn on TV, Set active Source to TV, go to home screen | OTP, and go to home screen | OTP, and go to home screen |
-| volume keys | Handle on device or send to soundbar | Send to TV or soundbar | Handle on device or send to TV |
+| Volume keys | Handle on device or send to soundbar | Send to TV or soundbar | Handle on device or send to TV |
+| Other keys | Forward to active source | Handle on device | Handle on device |
-Special cases and flags for each key are described below
+Special cases and flags per key are described below.
-## POWER
+## TV_POWER
### TV Panel
-TODO
+For ATV TV panel devices, TV_POWER is an alias of POWER.
-### OTT
+### Source Devices (OTT and Soundbar)
-TODO
+For ATV source devices with POWER_CONTROL_MODE set to none or CEC control disabled, TV_POWER is an alias of POWER.
-### Soundbar
+For all other source devices, TV_POWER toggles the TV power state and makes the OTT power state follow.
-TODO
+### Other Devices
+
+For any device that is not connected to a TV via HDMI and not an ATV device, TV_POWER is ignored.
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index bd577f3..016c5ed 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -1052,6 +1052,9 @@
public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId);
final String property = uri.getLastPathSegment();
+ if (property == null) {
+ return;
+ }
if (property.equals(getServiceSettingsProperty())
|| property.equals(Settings.Secure.USER_SETUP_COMPLETE)) {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bbe52bc..edb5d97 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -590,10 +590,13 @@
for (int i = viewports.size() - 1; i >= 0; --i) {
final DisplayViewport v = vArray[i] = viewports.get(i).makeCopy();
// deviceWidth/Height are apparently in "rotated" space, so flip them if needed.
- int dw = (v.orientation % 2) == 0 ? v.deviceWidth : v.deviceHeight;
- int dh = (v.orientation % 2) == 0 ? v.deviceHeight : v.deviceWidth;
- v.logicalFrame.set(0, 0, dw, dh);
- v.physicalFrame.set(0, 0, dw, dh);
+ if (v.orientation % 2 != 0) {
+ final int dw = v.deviceWidth;
+ v.deviceWidth = v.deviceHeight;
+ v.deviceHeight = dw;
+ }
+ v.logicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight);
+ v.physicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight);
v.orientation = 0;
}
} else {
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index d08980c..720be82 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -29,6 +29,7 @@
import android.view.ViewConfiguration;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -199,6 +200,8 @@
runRoll(inputSource, displayId);
} else if ("motionevent".equals(arg)) {
runMotionEvent(inputSource, displayId);
+ } else if ("keycombination".equals(arg)) {
+ runKeyCombination(inputSource, displayId);
} else {
handleDefaultCommands(arg);
}
@@ -224,7 +227,7 @@
out.println();
out.println("The commands and default sources are:");
out.println(" text <string> (Default: touchscreen)");
- out.println(" keyevent [--longpress] <key code number or name> ..."
+ out.println(" keyevent [--longpress|--doubletap] <key code number or name> ..."
+ " (Default: keyboard)");
out.println(" tap <x> <y> (Default: touchscreen)");
out.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]"
@@ -234,6 +237,8 @@
out.println(" press (Default: trackball)");
out.println(" roll <dx> <dy> (Default: trackball)");
out.println(" motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen)");
+ out.println(" keycombination <key code 1> <key code 2> ..."
+ + " (Default: keyboard)");
}
}
@@ -282,6 +287,14 @@
final boolean longpress = "--longpress".equals(arg);
if (longpress) {
arg = getNextArgRequired();
+ } else {
+ final boolean doubleTap = "--doubletap".equals(arg);
+ if (doubleTap) {
+ arg = getNextArgRequired();
+ final int keycode = KeyEvent.keyCodeFromString(arg);
+ sendKeyDoubleTap(inputSource, keycode, displayId);
+ return;
+ }
}
do {
@@ -292,22 +305,32 @@
private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) {
final long now = SystemClock.uptimeMillis();
- int repeatCount = 0;
- KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount,
+ KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0 /* repeatCount */,
0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
inputSource);
event.setDisplayId(displayId);
injectKeyEvent(event);
if (longpress) {
- repeatCount++;
- injectKeyEvent(KeyEvent.changeTimeRepeat(event, now, repeatCount,
+ // Some long press behavior would check the event time, we set a new event time here.
+ final long nextEventTime = now + ViewConfiguration.getGlobalActionKeyTimeout();
+ injectKeyEvent(KeyEvent.changeTimeRepeat(event, nextEventTime, 1 /* repeatCount */,
KeyEvent.FLAG_LONG_PRESS));
}
injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
}
+ private void sendKeyDoubleTap(int inputSource, int keyCode, int displayId) {
+ sendKeyEvent(inputSource, keyCode, false, displayId);
+ try {
+ Thread.sleep(ViewConfiguration.getDoubleTapMinTime());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ sendKeyEvent(inputSource, keyCode, false, displayId);
+ }
+
private void runTap(int inputSource, int displayId) {
inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
sendTap(inputSource, Float.parseFloat(getNextArgRequired()),
@@ -440,4 +463,59 @@
final long now = SystemClock.uptimeMillis();
injectMotionEvent(inputSource, action, now, now, x, y, pressure, displayId);
}
+
+ private void runKeyCombination(int inputSource, int displayId) {
+ String arg = getNextArgRequired();
+ ArrayList<Integer> keyCodes = new ArrayList<>();
+
+ while (arg != null) {
+ final int keyCode = KeyEvent.keyCodeFromString(arg);
+ if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+ throw new IllegalArgumentException("Unknown keycode: " + arg);
+ }
+ keyCodes.add(keyCode);
+ arg = getNextArg();
+ }
+
+ // At least 2 keys.
+ if (keyCodes.size() < 2) {
+ throw new IllegalArgumentException("keycombination requires at least 2 keycodes");
+ }
+
+ sendKeyCombination(inputSource, keyCodes, displayId);
+ }
+
+ private void injectKeyEventAsync(KeyEvent event) {
+ InputManager.getInstance().injectInputEvent(event,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }
+
+ private void sendKeyCombination(int inputSource, ArrayList<Integer> keyCodes, int displayId) {
+ final long now = SystemClock.uptimeMillis();
+ final int count = keyCodes.size();
+ final KeyEvent[] events = new KeyEvent[count];
+ for (int i = 0; i < count; i++) {
+ final KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCodes.get(i), 0,
+ 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
+ inputSource);
+ event.setDisplayId(displayId);
+ events[i] = event;
+ }
+
+ for (KeyEvent event: events) {
+ // Use async inject so interceptKeyBeforeQueueing or interceptKeyBeforeDispatching could
+ // handle keys.
+ injectKeyEventAsync(event);
+ }
+
+ try {
+ Thread.sleep(ViewConfiguration.getTapTimeout());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ for (KeyEvent event: events) {
+ injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1e66589..d41f4c7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2620,9 +2620,8 @@
}
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
// Dispatch display id for InputMethodService to update context display.
- executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
- MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken,
- mMethodMap.get(mCurMethodId).getConfigChanges()));
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
+ MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
scheduleNotifyImeUidToAudioService(mCurMethodUid);
if (mCurClient != null) {
clearClientSessionLocked(mCurClient);
@@ -3647,12 +3646,9 @@
hideCurrentInputLocked(mCurFocusedWindow, 0, null,
SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
}
- res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
- startInputFlags, startInputReason);
- } else {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
- startInputFlags, startInputReason);
}
+ res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
+ startInputFlags, startInputReason);
} else {
res = InputBindResult.NULL_EDITOR_INFO;
}
@@ -4467,8 +4463,7 @@
}
final IBinder token = (IBinder) args.arg2;
((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
- new InputMethodPrivilegedOperationsImpl(this, token),
- (int) args.arg3);
+ new InputMethodPrivilegedOperationsImpl(this, token));
} catch (RemoteException e) {
}
args.recycle();
@@ -5414,37 +5409,38 @@
@BinderThread
@ShellCommandResult
private int onCommandWithSystemIdentity(@Nullable String cmd) {
- if ("get-last-switch-user-id".equals(cmd)) {
- return mService.getLastSwitchUserId(this);
- }
-
- // For existing "adb shell ime <command>".
- if ("ime".equals(cmd)) {
- final String imeCommand = getNextArg();
- if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
- onImeCommandHelp();
- return ShellCommandResult.SUCCESS;
+ switch (TextUtils.emptyIfNull(cmd)) {
+ case "get-last-switch-user-id":
+ return mService.getLastSwitchUserId(this);
+ case "tracing":
+ return mService.handleShellCommandTraceInputMethod(this);
+ case "ime": { // For "adb shell ime <command>".
+ final String imeCommand = TextUtils.emptyIfNull(getNextArg());
+ switch (imeCommand) {
+ case "":
+ case "-h":
+ case "help":
+ return onImeCommandHelp();
+ case "list":
+ return mService.handleShellCommandListInputMethods(this);
+ case "enable":
+ return mService.handleShellCommandEnableDisableInputMethod(this, true);
+ case "disable":
+ return mService.handleShellCommandEnableDisableInputMethod(this, false);
+ case "set":
+ return mService.handleShellCommandSetInputMethod(this);
+ case "reset":
+ return mService.handleShellCommandResetInputMethod(this);
+ case "tracing": // TODO(b/180765389): Unsupport "adb shell ime tracing"
+ return mService.handleShellCommandTraceInputMethod(this);
+ default:
+ getOutPrintWriter().println("Unknown command: " + imeCommand);
+ return ShellCommandResult.FAILURE;
+ }
}
- switch (imeCommand) {
- case "list":
- return mService.handleShellCommandListInputMethods(this);
- case "enable":
- return mService.handleShellCommandEnableDisableInputMethod(this, true);
- case "disable":
- return mService.handleShellCommandEnableDisableInputMethod(this, false);
- case "set":
- return mService.handleShellCommandSetInputMethod(this);
- case "reset":
- return mService.handleShellCommandResetInputMethod(this);
- case "tracing":
- return mService.handleShellCommandTraceInputMethod(this);
- default:
- getOutPrintWriter().println("Unknown command: " + imeCommand);
- return ShellCommandResult.FAILURE;
- }
+ default:
+ return handleDefaultCommands(cmd);
}
-
- return handleDefaultCommands(cmd);
}
@BinderThread
@@ -5458,10 +5454,16 @@
pw.println(" Synonym of dumpsys.");
pw.println(" ime <command> [options]");
pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
+ pw.println(" tracing <command>");
+ pw.println(" start: Start tracing.");
+ pw.println(" stop : Stop tracing.");
+ pw.println(" help : Show help.");
}
}
- private void onImeCommandHelp() {
+ @BinderThread
+ @ShellCommandResult
+ private int onImeCommandHelp() {
try (IndentingPrintWriter pw =
new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
pw.println("ime <command>:");
@@ -5516,6 +5518,7 @@
pw.decreaseIndent();
}
+ return ShellCommandResult.SUCCESS;
}
}
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
index 7b400b6..6ea4bd2 100644
--- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -17,7 +17,6 @@
package com.android.server.location;
import android.annotation.Nullable;
-import android.content.ComponentName;
import android.content.Context;
import android.hardware.location.ActivityRecognitionHardware;
import android.hardware.location.IActivityRecognitionHardwareClient;
@@ -27,6 +26,7 @@
import android.util.Log;
import com.android.server.ServiceWatcher;
+import com.android.server.ServiceWatcher.BoundService;
/**
* Proxy class to bind GmsCore to the ActivityRecognitionHardware.
@@ -82,7 +82,7 @@
return resolves;
}
- private void onBind(IBinder binder, ComponentName service) throws RemoteException {
+ private void onBind(IBinder binder, BoundService service) throws RemoteException {
String descriptor = binder.getInterfaceDescriptor();
if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index cbbc981..2920ddb 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -52,6 +52,7 @@
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementRequest;
import android.location.IGeocodeListener;
+import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssNmeaListener;
@@ -63,6 +64,7 @@
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.OnProviderLocationTagsChangeListener;
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
@@ -82,6 +84,7 @@
import android.provider.Settings;
import android.stats.location.LocationStatsEnums;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -255,6 +258,9 @@
final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
new CopyOnWriteArrayList<>();
+ @GuardedBy("mLock")
+ private @Nullable OnProviderLocationTagsChangeListener mOnProviderLocationTagsChangeListener;
+
LocationManagerService(Context context, Injector injector, LocationEventLog eventLog) {
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mInjector = injector;
@@ -319,8 +325,9 @@
Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);
manager.startManager();
+ manager.setOnProviderLocationTagsChangeListener(
+ mOnProviderLocationTagsChangeListener);
if (realProvider != null) {
-
// custom logic wrapping all non-passive providers
if (manager != mPassiveManager) {
boolean enableStationaryThrottling = Settings.Global.getInt(
@@ -331,7 +338,6 @@
mInjector, realProvider, mEventLog);
}
}
-
manager.setRealProvider(realProvider);
}
mProviderManagers.add(manager);
@@ -456,8 +462,9 @@
.setPowerUsage(Integer.parseInt(fragments[8]))
.setAccuracy(Integer.parseInt(fragments[9]))
.build();
- getOrAddLocationProviderManager(name).setMockProvider(
- new MockLocationProvider(properties, CallerIdentity.fromContext(mContext)));
+ final LocationProviderManager manager = getOrAddLocationProviderManager(name);
+ manager.setMockProvider(new MockLocationProvider(properties,
+ CallerIdentity.fromContext(mContext), Collections.emptySet()));
}
}
@@ -924,6 +931,22 @@
}
@Override
+ public void addGnssAntennaInfoListener(IGnssAntennaInfoListener listener, String packageName,
+ @Nullable String attributionTag, String listenerId) {
+ if (mGnssManagerService != null) {
+ mGnssManagerService.addGnssAntennaInfoListener(listener, packageName, attributionTag,
+ listenerId);
+ }
+ }
+
+ @Override
+ public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) {
+ if (mGnssManagerService != null) {
+ mGnssManagerService.removeGnssAntennaInfoListener(listener);
+ }
+ }
+
+ @Override
public void addProviderRequestListener(IProviderRequestListener listener) {
for (LocationProviderManager manager : mProviderManagers) {
manager.addProviderRequestListener(listener);
@@ -1147,15 +1170,16 @@
@Override
public void addTestProvider(String provider, ProviderProperties properties,
- String packageName, String attributionTag) {
+ List<String> extraAttributionTags, String packageName, String attributionTag) {
// unsafe is ok because app ops will verify the package name
CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
- getOrAddLocationProviderManager(provider).setMockProvider(
- new MockLocationProvider(properties, identity));
+ final LocationProviderManager manager = getOrAddLocationProviderManager(provider);
+ manager.setMockProvider(new MockLocationProvider(properties, identity,
+ new ArraySet<>(extraAttributionTags)));
}
@Override
@@ -1392,6 +1416,19 @@
return new LocationTime(location.getTime(), location.getElapsedRealtimeNanos());
}
+
+ @Override
+ public void setOnProviderLocationTagsChangeListener(
+ @Nullable OnProviderLocationTagsChangeListener listener) {
+ synchronized (mLock) {
+ mOnProviderLocationTagsChangeListener = listener;
+ final int providerCount = mProviderManagers.size();
+ for (int i = 0; i < providerCount; i++) {
+ final LocationProviderManager manager = mProviderManagers.get(i);
+ manager.setOnProviderLocationTagsChangeListener(listener);
+ }
+ }
+ }
}
private static class SystemInjector implements Injector {
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
index f0dd8b5..5dc3ed8 100644
--- a/services/core/java/com/android/server/location/LocationShellCommand.java
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -26,6 +26,8 @@
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -50,15 +52,11 @@
switch (cmd) {
case "is-location-enabled": {
- int userId = parseUserId();
- boolean enabled = mService.isLocationEnabledForUser(userId);
- getOutPrintWriter().println(enabled);
+ handleIsLocationEnabled();
return 0;
}
case "set-location-enabled": {
- int userId = parseUserId();
- boolean enabled = Boolean.parseBoolean(getNextArgRequired());
- mService.setLocationEnabledForUser(enabled, userId);
+ handleSetLocationEnabled();
return 0;
}
case "providers": {
@@ -73,36 +71,23 @@
private int parseProvidersCommand(String cmd) {
switch (cmd) {
case "add-test-provider": {
- String provider = getNextArgRequired();
- ProviderProperties properties = parseTestProviderProviderProperties();
- mService.addTestProvider(provider, properties, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ handleAddTestProvider();
return 0;
}
case "remove-test-provider": {
- String provider = getNextArgRequired();
- mService.removeTestProvider(provider, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ handleRemoveTestProvider();
return 0;
}
case "set-test-provider-enabled": {
- String provider = getNextArgRequired();
- boolean enabled = Boolean.parseBoolean(getNextArgRequired());
- mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ handleSetTestProviderEnabled();
return 0;
}
case "set-test-provider-location": {
- String provider = getNextArgRequired();
- Location location = parseTestProviderLocation(provider);
- mService.setTestProviderLocation(provider, location, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ handleSetTestProviderLocation();
return 0;
}
case "send-extra-command": {
- String provider = getNextArgRequired();
- String command = getNextArgRequired();
- mService.sendExtraCommand(provider, command, null);
+ handleSendExtraCommand();
return 0;
}
default:
@@ -110,21 +95,47 @@
}
}
- private int parseUserId() {
- final String option = getNextOption();
- if (option != null) {
- if (option.equals("--user")) {
- return UserHandle.parseUserArg(getNextArgRequired());
- } else {
- throw new IllegalArgumentException(
- "Expected \"--user\" option, but got \"" + option + "\" instead");
- }
- }
+ private void handleIsLocationEnabled() {
+ int userId = UserHandle.USER_CURRENT_OR_SELF;
- return UserHandle.USER_CURRENT_OR_SELF;
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
+ if ("--user".equals(option)) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + option);
+ }
+ } while (true);
+
+ getOutPrintWriter().println(mService.isLocationEnabledForUser(userId));
}
- private ProviderProperties parseTestProviderProviderProperties() {
+ private void handleSetLocationEnabled() {
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+
+ int userId = UserHandle.USER_CURRENT_OR_SELF;
+
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
+ if ("--user".equals(option)) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + option);
+ }
+ } while (true);
+
+ mService.setLocationEnabledForUser(enabled, userId);
+ }
+
+ private void handleAddTestProvider() {
+ String provider = getNextArgRequired();
+
boolean requiresNetwork = false;
boolean requiresSatellite = false;
boolean requiresCell = false;
@@ -135,8 +146,13 @@
int powerRequirement = Criteria.POWER_LOW;
int accuracy = Criteria.ACCURACY_FINE;
- String option = getNextOption();
- while (option != null) {
+ List<String> extraAttributionTags = Collections.emptyList();
+
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
switch (option) {
case "--requiresNetwork": {
requiresNetwork = true;
@@ -174,12 +190,15 @@
accuracy = Integer.parseInt(getNextArgRequired());
break;
}
+ case "--extraAttributionTags": {
+ extraAttributionTags = Arrays.asList(getNextArgRequired().split(","));
+ break;
+ }
default:
throw new IllegalArgumentException(
"Received unexpected option: " + option);
}
- option = getNextOption();
- }
+ } while(true);
ProviderProperties properties = new ProviderProperties.Builder()
.setHasNetworkRequirement(requiresNetwork)
@@ -192,30 +211,50 @@
.setPowerUsage(powerRequirement)
.setAccuracy(accuracy)
.build();
-
- return properties;
+ mService.addTestProvider(provider, properties, extraAttributionTags,
+ mContext.getOpPackageName(), mContext.getAttributionTag());
}
- private Location parseTestProviderLocation(String provider) {
- boolean hasLatitude = false;
- boolean hasLongitude = false;
+ private void handleRemoveTestProvider() {
+ String provider = getNextArgRequired();
+ mService.removeTestProvider(provider, mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ }
+
+ private void handleSetTestProviderEnabled() {
+ String provider = getNextArgRequired();
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ }
+
+ private void handleSetTestProviderLocation() {
+ String provider = getNextArgRequired();
+
+ boolean hasLatLng = false;
Location location = new Location(provider);
location.setAccuracy(DEFAULT_TEST_LOCATION_ACCURACY);
location.setTime(System.currentTimeMillis());
+ location.setElapsedRealtimeNanos(System.nanoTime());
- String option = getNextOption();
- while (option != null) {
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
switch (option) {
case "--location": {
String[] locationInput = getNextArgRequired().split(",");
if (locationInput.length != 2) {
- throw new IllegalArgumentException(
- "Unexpected location format: " + Arrays.toString(locationInput));
+ throw new IllegalArgumentException("Location argument must be in the form "
+ + "of \"<LATITUDE>,<LONGITUDE>\", not "
+ + Arrays.toString(locationInput));
}
location.setLatitude(Double.parseDouble(locationInput[0]));
location.setLongitude(Double.parseDouble(locationInput[1]));
+ hasLatLng = true;
break;
}
case "--accuracy": {
@@ -227,15 +266,22 @@
break;
}
default:
- throw new IllegalArgumentException(
- "Received unexpected option: " + option);
+ throw new IllegalArgumentException("Unknown option: " + option);
}
- option = getNextOption();
+ } while (true);
+
+ if (!hasLatLng) {
+ throw new IllegalArgumentException("Option \"--location\" is required");
}
- location.setElapsedRealtimeNanos(System.nanoTime());
+ mService.setTestProviderLocation(provider, location, mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ }
- return location;
+ private void handleSendExtraCommand() {
+ String provider = getNextArgRequired();
+ String command = getNextArgRequired();
+ mService.sendExtraCommand(provider, command, null);
}
@Override
@@ -245,24 +291,29 @@
pw.println(" help or -h");
pw.println(" Print this help text.");
pw.println(" is-location-enabled [--user <USER_ID>]");
- pw.println(" Gets the master location switch enabled state.");
- pw.println(" set-location-enabled [--user <USER_ID>] true|false");
- pw.println(" Sets the master location switch enabled state.");
+ pw.println(" Gets the master location switch enabled state. If no user is specified,");
+ pw.println(" the current user is assumed.");
+ pw.println(" set-location-enabled true|false [--user <USER_ID>]");
+ pw.println(" Sets the master location switch enabled state. If no user is specified,");
+ pw.println(" the current user is assumed.");
pw.println(" providers");
+ pw.println(" The providers command is followed by a subcommand, as listed below:");
+ pw.println();
pw.println(" add-test-provider <PROVIDER> [--requiresNetwork] [--requiresSatellite]");
pw.println(" [--requiresCell] [--hasMonetaryCost] [--supportsAltitude]");
pw.println(" [--supportsSpeed] [--supportsBearing]");
pw.println(" [--powerRequirement <POWER_REQUIREMENT>]");
+ pw.println(" [--extraAttributionTags <TAG>,<TAG>,...]");
pw.println(" Add the given test provider. Requires MOCK_LOCATION permissions which");
pw.println(" can be enabled by running \"adb shell appops set <uid>");
pw.println(" android:mock_location allow\". There are optional flags that can be");
- pw.println(" used to configure the provider properties. If no flags are included,");
- pw.println(" then default values will be used.");
+ pw.println(" used to configure the provider properties and additional arguments. If");
+ pw.println(" no flags are included, then default values will be used.");
pw.println(" remove-test-provider <PROVIDER>");
pw.println(" Remove the given test provider.");
pw.println(" set-test-provider-enabled <PROVIDER> true|false");
pw.println(" Sets the given test provider enabled state.");
- pw.println(" set-test-provider-location <PROVIDER> [--location <LATITUDE>,<LONGITUDE>]");
+ pw.println(" set-test-provider-location <PROVIDER> --location <LATITUDE>,<LONGITUDE>");
pw.println(" [--accuracy <ACCURACY>] [--time <TIME>]");
pw.println(" Set location for given test provider. Accuracy and time are optional.");
pw.println(" send-extra-command <PROVIDER> <COMMAND>");
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 81c1e45..dde45c4 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -295,7 +295,7 @@
};
SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
manager.addSensorPrivacyListener(
- SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE, listener);
+ SensorPrivacyManager.Sensors.MICROPHONE, listener);
}
}
@@ -1079,8 +1079,8 @@
*/
private void sendMicrophoneDisableSettingUpdate() {
SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
- boolean disabled = manager.isIndividualSensorPrivacyEnabled(
- SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE);
+ boolean disabled = manager.isSensorPrivacyEnabled(
+ SensorPrivacyManager.Sensors.MICROPHONE);
Log.d(TAG, "Mic Disabled Setting: " + disabled);
mContextHubWrapper.onMicrophoneDisableSettingChanged(disabled);
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
new file mode 100644
index 0000000..1967e02
--- /dev/null
+++ b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss;
+
+import static com.android.server.location.gnss.GnssManagerService.TAG;
+
+import android.annotation.Nullable;
+import android.location.GnssAntennaInfo;
+import android.location.IGnssAntennaInfoListener;
+import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
+import android.os.IBinder;
+
+import com.android.server.location.gnss.hal.GnssNative;
+import com.android.server.location.listeners.BinderListenerRegistration;
+import com.android.server.location.listeners.ListenerMultiplexer;
+import com.android.server.location.listeners.ListenerRegistration;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Antenna info HAL module and listener multiplexer.
+ */
+public class GnssAntennaInfoProvider extends
+ ListenerMultiplexer<IBinder, IGnssAntennaInfoListener,
+ ListenerRegistration<IGnssAntennaInfoListener>, Void> implements
+ GnssNative.BaseCallbacks, GnssNative.AntennaInfoCallbacks {
+
+ /**
+ * Registration object for GNSS listeners.
+ */
+ protected class AntennaInfoListenerRegistration extends
+ BinderListenerRegistration<Void, IGnssAntennaInfoListener> {
+
+ protected AntennaInfoListenerRegistration(CallerIdentity callerIdentity,
+ IGnssAntennaInfoListener listener) {
+ super(null, callerIdentity, listener);
+ }
+
+ @Override
+ protected GnssAntennaInfoProvider getOwner() {
+ return GnssAntennaInfoProvider.this;
+ }
+ }
+
+ private final GnssNative mGnssNative;
+
+ private volatile @Nullable List<GnssAntennaInfo> mAntennaInfos;
+
+ GnssAntennaInfoProvider(GnssNative gnssNative) {
+ mGnssNative = gnssNative;
+ mGnssNative.addBaseCallbacks(this);
+ mGnssNative.addAntennaInfoCallbacks(this);
+ }
+
+ @Nullable List<GnssAntennaInfo> getAntennaInfos() {
+ return mAntennaInfos;
+ }
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
+ public boolean isSupported() {
+ return mGnssNative.isAntennaInfoSupported();
+ }
+
+ public void addListener(CallerIdentity callerIdentity, IGnssAntennaInfoListener listener) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ putRegistration(listener.asBinder(),
+ new AntennaInfoListenerRegistration(callerIdentity, listener));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public void removeListener(IGnssAntennaInfoListener listener) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeRegistration(listener.asBinder());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ protected boolean registerWithService(Void merged,
+ Collection<ListenerRegistration<IGnssAntennaInfoListener>> listenerRegistrations) {
+ return true;
+ }
+
+ @Override
+ protected void unregisterWithService() {}
+
+ @Override
+ protected boolean isActive(ListenerRegistration<IGnssAntennaInfoListener> registration) {
+ return true;
+ }
+
+ @Override
+ protected Void mergeRegistrations(
+ Collection<ListenerRegistration<IGnssAntennaInfoListener>> listenerRegistrations) {
+ return null;
+ }
+
+ @Override
+ public void onHalStarted() {
+ mGnssNative.startAntennaInfoListening();
+ }
+
+ @Override
+ public void onHalRestarted() {
+ mGnssNative.startAntennaInfoListening();
+ }
+
+ @Override
+ public void onReportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
+ if (antennaInfos.equals(mAntennaInfos)) {
+ return;
+ }
+
+ mAntennaInfos = antennaInfos;
+ deliverToListeners(listener -> {
+ listener.onGnssAntennaInfoChanged(antennaInfos);
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 87e6ef4..5e6ae68 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -229,7 +229,7 @@
* registrations will be treated as inactive and the backing service will never be registered.
*
*/
- protected boolean isServiceSupported() {
+ public boolean isSupported() {
return true;
}
@@ -276,7 +276,7 @@
@Override
protected boolean isActive(GnssListenerRegistration registration) {
- if (!isServiceSupported()) {
+ if (!isSupported()) {
return false;
}
@@ -339,7 +339,7 @@
@Override
protected void onRegister() {
- if (!isServiceSupported()) {
+ if (!isSupported()) {
return;
}
@@ -356,7 +356,7 @@
@Override
protected void onUnregister() {
- if (!isServiceSupported()) {
+ if (!isSupported()) {
return;
}
@@ -404,7 +404,7 @@
@Override
protected String getServiceState() {
- if (!isServiceSupported()) {
+ if (!isSupported()) {
return "unsupported";
} else {
return super.getServiceState();
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 9216a6b..1df29ab 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -103,6 +103,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -371,7 +372,8 @@
public GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative,
GnssMetrics gnssMetrics) {
- super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES);
+ super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES,
+ Collections.emptySet());
mContext = context;
mGnssNative = gnssNative;
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 8312c63..bcdfed4 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -27,6 +27,7 @@
import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementRequest;
+import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssNmeaListener;
@@ -49,7 +50,6 @@
import com.android.server.location.injector.Injector;
import java.io.FileDescriptor;
-import java.util.ArrayList;
import java.util.List;
/** Manages Gnss providers and related Gnss functions for LocationManagerService. */
@@ -68,11 +68,11 @@
private final GnssNmeaProvider mGnssNmeaProvider;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
+ private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
private final IGpsGeofenceHardware mGnssGeofenceProxy;
private final GnssGeofenceHalModule mGeofenceHalModule;
private final GnssCapabilitiesHalModule mCapabilitiesHalModule;
- private final GnssAntennaInfoHalModule mAntennaInfoHalModule;
private final GnssMetrics mGnssMetrics;
@@ -89,11 +89,11 @@
mGnssNmeaProvider = new GnssNmeaProvider(injector, mGnssNative);
mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector, mGnssNative);
mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector, mGnssNative);
+ mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(mGnssNative);
mGnssGeofenceProxy = new GnssGeofenceProxy(mGnssNative);
mGeofenceHalModule = new GnssGeofenceHalModule(mGnssNative);
mCapabilitiesHalModule = new GnssCapabilitiesHalModule(mGnssNative);
- mAntennaInfoHalModule = new GnssAntennaInfoHalModule(mGnssNative);
// allow gnss access to begin - we must assume that callbacks can start immediately
mGnssNative.register();
@@ -140,7 +140,7 @@
* Get GNSS antenna information.
*/
public @Nullable List<GnssAntennaInfo> getGnssAntennaInfos() {
- return mAntennaInfoHalModule.getAntennaInfos();
+ return mGnssAntennaInfoProvider.getAntennaInfos();
}
/**
@@ -242,6 +242,24 @@
}
/**
+ * Adds a GNSS antenna info listener.
+ */
+ public void addGnssAntennaInfoListener(IGnssAntennaInfoListener listener, String packageName,
+ @Nullable String attributionTag, String listenerId) {
+
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
+ listenerId);
+ mGnssAntennaInfoProvider.addListener(identity, listener);
+ }
+
+ /**
+ * Removes a GNSS antenna info listener.
+ */
+ public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) {
+ mGnssAntennaInfoProvider.removeListener(listener);
+ }
+
+ /**
* Send Ni Response, indicating a location request initiated by a network carrier.
*/
public void sendNiResponse(int notifId, int userResponse) {
@@ -263,25 +281,34 @@
ipw.println("Capabilities: " + mGnssNative.getCapabilities());
- List<GnssAntennaInfo> infos = mAntennaInfoHalModule.getAntennaInfos();
- if (infos != null) {
- ipw.println("Antenna Infos: " + infos);
+ if (mGnssStatusProvider.isSupported()) {
+ ipw.println("Status Provider:");
+ ipw.increaseIndent();
+ mGnssStatusProvider.dump(fd, ipw, args);
+ ipw.decreaseIndent();
}
- ipw.println("Measurements Provider:");
- ipw.increaseIndent();
- mGnssMeasurementsProvider.dump(fd, ipw, args);
- ipw.decreaseIndent();
+ if (mGnssMeasurementsProvider.isSupported()) {
+ ipw.println("Measurements Provider:");
+ ipw.increaseIndent();
+ mGnssMeasurementsProvider.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
- ipw.println("Navigation Message Provider:");
- ipw.increaseIndent();
- mGnssNavigationMessageProvider.dump(fd, ipw, args);
- ipw.decreaseIndent();
+ if (mGnssNavigationMessageProvider.isSupported()) {
+ ipw.println("Navigation Message Provider:");
+ ipw.increaseIndent();
+ mGnssNavigationMessageProvider.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
- ipw.println("Status Provider:");
- ipw.increaseIndent();
- mGnssStatusProvider.dump(fd, ipw, args);
- ipw.decreaseIndent();
+ if (mGnssAntennaInfoProvider.isSupported()) {
+ ipw.println("Navigation Message Provider:");
+ ipw.increaseIndent();
+ ipw.println("Antenna Infos: " + mGnssAntennaInfoProvider.getAntennaInfos());
+ mGnssAntennaInfoProvider.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
GnssPowerStats powerStats = mGnssNative.getPowerStats();
if (powerStats != null) {
@@ -399,53 +426,4 @@
}
}
}
-
- private class GnssAntennaInfoHalModule implements GnssNative.BaseCallbacks,
- GnssNative.AntennaInfoCallbacks {
-
- private final GnssNative mGnssNative;
-
- private volatile @Nullable List<GnssAntennaInfo> mAntennaInfos;
-
- GnssAntennaInfoHalModule(GnssNative gnssNative) {
- mGnssNative = gnssNative;
- mGnssNative.addBaseCallbacks(this);
- mGnssNative.addAntennaInfoCallbacks(this);
- }
-
- @Nullable List<GnssAntennaInfo> getAntennaInfos() {
- return mAntennaInfos;
- }
-
- @Override
- public void onHalStarted() {
- mGnssNative.startAntennaInfoListening();
- }
-
- @Override
- public void onHalRestarted() {
- mGnssNative.startAntennaInfoListening();
- }
-
- @Override
- public void onReportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
- if (antennaInfos.equals(mAntennaInfos)) {
- return;
- }
-
- mAntennaInfos = antennaInfos;
-
- long ident = Binder.clearCallingIdentity();
- try {
- Intent intent = new Intent(LocationManager.ACTION_GNSS_ANTENNA_INFOS_CHANGED)
- .putParcelableArrayListExtra(LocationManager.EXTRA_GNSS_ANTENNA_INFOS,
- new ArrayList<>(antennaInfos))
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 305bc9b..b3119d7 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -99,7 +99,7 @@
}
@Override
- protected boolean isServiceSupported() {
+ public boolean isSupported() {
return mGnssNative.isMeasurementSupported();
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
index ff9ad65..e9fce05 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
@@ -70,7 +70,7 @@
}
@Override
- protected boolean isServiceSupported() {
+ public boolean isSupported() {
return mGnssNative.isNavigationMessageCollectionSupported();
}
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index 7e2f089..f275663 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -699,11 +699,11 @@
}
/**
- * Returns true if antenna info listening is supported.
+ * Returns true if antenna info is supported.
*/
- public boolean isAntennaInfoListeningSupported() {
+ public boolean isAntennaInfoSupported() {
Preconditions.checkState(mRegistered);
- return mGnssHal.isAntennaInfoListeningSupported();
+ return mGnssHal.isAntennaInfoSupported();
}
/**
@@ -1259,7 +1259,7 @@
return native_stop_navigation_message_collection();
}
- protected boolean isAntennaInfoListeningSupported() {
+ protected boolean isAntennaInfoSupported() {
return native_is_antenna_info_supported();
}
diff --git a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
index 08deb869..ba7f44f 100644
--- a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
@@ -28,7 +28,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Collections;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
@@ -65,9 +67,10 @@
/**
* Default state value for a location provider that is disabled with no properties and an
- * empty provider package list.
+ * empty extra attribution tag set.
*/
- public static final State EMPTY_STATE = new State(false, null, null);
+ public static final State EMPTY_STATE = new State(false, null, null,
+ Collections.emptySet());
/**
* The provider's allowed state.
@@ -84,10 +87,18 @@
*/
@Nullable public final CallerIdentity identity;
- private State(boolean allowed, ProviderProperties properties, CallerIdentity identity) {
+ /**
+ * A set of attribution tags also associated with this provider - these attribution tags may
+ * be afforded special privileges.
+ */
+ public final Set<String> extraAttributionTags;
+
+ private State(boolean allowed, ProviderProperties properties, CallerIdentity identity,
+ Set<String> extraAttributionTags) {
this.allowed = allowed;
this.properties = properties;
this.identity = identity;
+ this.extraAttributionTags = Objects.requireNonNull(extraAttributionTags);
}
/**
@@ -97,7 +108,7 @@
if (allowed == this.allowed) {
return this;
} else {
- return new State(allowed, properties, identity);
+ return new State(allowed, properties, identity, extraAttributionTags);
}
}
@@ -108,7 +119,7 @@
if (Objects.equals(properties, this.properties)) {
return this;
} else {
- return new State(allowed, properties, identity);
+ return new State(allowed, properties, identity, extraAttributionTags);
}
}
@@ -119,10 +130,22 @@
if (Objects.equals(identity, this.identity)) {
return this;
} else {
- return new State(allowed, properties, identity);
+ return new State(allowed, properties, identity, extraAttributionTags);
}
}
+ /**
+ * Returns a state the same as the current but with extra attribution tags set as specified.
+ */
+ public State withExtraAttributionTags(Set<String> extraAttributionTags) {
+ if (extraAttributionTags.equals(this.extraAttributionTags)) {
+ return this;
+ } else {
+ return new State(allowed, properties, identity, extraAttributionTags);
+ }
+ }
+
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -133,12 +156,13 @@
}
State state = (State) o;
return allowed == state.allowed && properties == state.properties
- && Objects.equals(identity, state.identity);
+ && Objects.equals(identity, state.identity)
+ && extraAttributionTags.equals(state.extraAttributionTags);
}
@Override
public int hashCode() {
- return Objects.hash(allowed, properties, identity);
+ return Objects.hash(allowed, properties, identity, extraAttributionTags);
}
}
@@ -195,13 +219,14 @@
* An optional identity and properties may be provided to initialize the location provider.
*/
protected AbstractLocationProvider(Executor executor, @Nullable CallerIdentity identity,
- @Nullable ProviderProperties properties) {
+ @Nullable ProviderProperties properties, Set<String> extraAttributionTags) {
Preconditions.checkArgument(identity == null || identity.getListenerId() == null);
- mExecutor = executor;
+ mExecutor = Objects.requireNonNull(executor);
mInternalState = new AtomicReference<>(new InternalState(null,
State.EMPTY_STATE
.withIdentity(identity)
- .withProperties(properties)));
+ .withProperties(properties)
+ .withExtraAttributionTags(extraAttributionTags)));
mController = new Controller();
}
@@ -273,7 +298,7 @@
}
/**
- * Call this method to report a change in provider packages.
+ * Call this method to report a change in the provider's identity.
*/
protected void setIdentity(@Nullable CallerIdentity identity) {
Preconditions.checkArgument(identity == null || identity.getListenerId() == null);
@@ -281,6 +306,13 @@
}
/**
+ * Call this method to report a change in the provider's extra attribution tags.
+ */
+ protected void setExtraAttributionTags(Set<String> extraAttributionTags) {
+ setState(state -> state.withExtraAttributionTags(extraAttributionTags));
+ }
+
+ /**
* Call this method to report a new location.
*/
protected void reportLocation(LocationResult locationResult) {
diff --git a/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java b/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java
index a3ec867..423f833 100644
--- a/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java
@@ -24,6 +24,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Collections;
import java.util.concurrent.Executor;
/**
@@ -40,7 +41,7 @@
private boolean mInitialized = false;
DelegateLocationProvider(Executor executor, AbstractLocationProvider delegate) {
- super(executor, null, null);
+ super(executor, null, null, Collections.emptySet());
mDelegate = delegate;
}
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 5a35d7f..2aa6f28 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -29,6 +29,8 @@
import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+import static android.os.PowerWhitelistManager.REASON_LOCATION_PROVIDER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
@@ -52,6 +54,8 @@
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.LocationTagInfo;
+import android.location.LocationManagerInternal.OnProviderLocationTagsChangeListener;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
import android.location.LocationResult;
@@ -85,6 +89,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.location.LocationPermissions;
@@ -117,6 +122,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
@@ -223,7 +229,10 @@
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDontSendToRestrictedApps(true);
// allows apps to start a fg service in response to a location PI
- options.setTemporaryAppWhitelistDuration(TEMPORARY_APP_ALLOWLIST_DURATION_MS);
+ options.setTemporaryAppAllowlist(TEMPORARY_APP_ALLOWLIST_DURATION_MS,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_LOCATION_PROVIDER,
+ "");
Intent intent = new Intent().putExtra(KEY_LOCATION_CHANGED,
locationResult.getLastLocation());
@@ -1288,6 +1297,9 @@
@GuardedBy("mLock")
private @Nullable OnAlarmListener mDelayedRegister;
+ @GuardedBy("mLock")
+ private @Nullable OnProviderLocationTagsChangeListener mOnLocationTagsChangeListener;
+
public LocationProviderManager(Context context, Injector injector, LocationEventLog eventLog,
String name, @Nullable PassiveLocationProviderManager passiveManager) {
mContext = context;
@@ -1448,6 +1460,19 @@
}
}
+ /**
+ * Registers a listener for the location tags of the provider.
+ *
+ * @param listener The listener
+ */
+ public void setOnProviderLocationTagsChangeListener(
+ @Nullable OnProviderLocationTagsChangeListener listener) {
+ Preconditions.checkArgument(mOnLocationTagsChangeListener == null || listener == null);
+ synchronized (mLock) {
+ mOnLocationTagsChangeListener = listener;
+ }
+ }
+
public void setMockProvider(@Nullable MockLocationProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mState != STATE_STOPPED);
@@ -2244,6 +2269,27 @@
if (oldState.allowed != newState.allowed) {
onEnabledChanged(UserHandle.USER_ALL);
}
+
+ if (mOnLocationTagsChangeListener != null) {
+ if (!oldState.extraAttributionTags.equals(newState.extraAttributionTags)) {
+ if (oldState.identity != null) {
+ FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ OnProviderLocationTagsChangeListener::onLocationTagsChanged,
+ mOnLocationTagsChangeListener, new LocationTagInfo(
+ oldState.identity.getUid(), oldState.identity.getPackageName(),
+ Collections.emptySet())
+ ));
+ }
+ if (newState.identity != null) {
+ FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ OnProviderLocationTagsChangeListener::onLocationTagsChanged,
+ mOnLocationTagsChangeListener, new LocationTagInfo(
+ newState.identity.getUid(), newState.identity.getPackageName(),
+ newState.extraAttributionTags)
+ ));
+ }
+ }
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/location/provider/MockLocationProvider.java b/services/core/java/com/android/server/location/provider/MockLocationProvider.java
index 0d8f643..52b04d4 100644
--- a/services/core/java/com/android/server/location/provider/MockLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/MockLocationProvider.java
@@ -28,6 +28,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Set;
/**
* A mock location provider used by LocationManagerService to implement test providers.
@@ -38,9 +39,10 @@
@Nullable private Location mLocation;
- public MockLocationProvider(ProviderProperties properties, CallerIdentity identity) {
+ public MockLocationProvider(ProviderProperties properties, CallerIdentity identity,
+ Set<String> extraAttributionTags) {
// using a direct executor is ok because this class has no locks that could deadlock
- super(DIRECT_EXECUTOR, identity, properties);
+ super(DIRECT_EXECUTOR, identity, properties, extraAttributionTags);
}
/** Sets the allowed state of this mock provider. */
diff --git a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
index cb7264e..8193644 100644
--- a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
@@ -31,6 +31,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Collections;
/**
* Represents a location provider that may switch between a mock implementation and a real
@@ -75,7 +76,7 @@
public MockableLocationProvider(Object ownerLock) {
// using a direct executor is acceptable because all inbound calls are delegated to the
// actual provider implementations which will use their own executors
- super(DIRECT_EXECUTOR, null, null);
+ super(DIRECT_EXECUTOR, null, null, Collections.emptySet());
mOwnerLock = ownerLock;
mRequest = ProviderRequest.EMPTY_REQUEST;
}
diff --git a/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java b/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
index a5758a3..68ede88 100644
--- a/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
@@ -30,6 +30,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Collections;
/**
* A passive location provider reports locations received from other providers
@@ -47,7 +48,8 @@
public PassiveLocationProvider(Context context) {
// using a direct executor is ok because this class has no locks that could deadlock
- super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context), PROPERTIES);
+ super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context), PROPERTIES,
+ Collections.emptySet());
setAllowed(true);
}
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index 4c97f64..44b62b3 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -32,15 +32,18 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.ArraySet;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.server.ServiceWatcher;
+import com.android.server.ServiceWatcher.BoundService;
import com.android.server.location.provider.AbstractLocationProvider;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -49,6 +52,9 @@
*/
public class ProxyLocationProvider extends AbstractLocationProvider {
+ private static final String KEY_EXTRA_ATTRIBUTION_TAGS = "android:location_allow_listed_tags";
+ private static final String EXTRA_ATTRIBUTION_TAGS_SEPARATOR = ";";
+
/**
* Creates and registers this proxy. If no suitable service is available for the proxy, returns
* null.
@@ -84,7 +90,7 @@
int nonOverlayPackageResId) {
// safe to use direct executor since our locks are not acquired in a code path invoked by
// our owning provider
- super(DIRECT_EXECUTOR, null, null);
+ super(DIRECT_EXECUTOR, null, null, Collections.emptySet());
mContext = context;
mServiceWatcher = new ServiceWatcher(context, action, this::onBind,
@@ -98,12 +104,22 @@
return mServiceWatcher.checkServiceResolves();
}
- private void onBind(IBinder binder, ComponentName service) throws RemoteException {
+ private void onBind(IBinder binder, BoundService boundService) throws RemoteException {
ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
synchronized (mLock) {
mProxy = new Proxy();
- mService = service;
+ mService = boundService.component;
+
+ // update extra attribution tag info from manifest
+ if (boundService.metadata != null) {
+ String tagsList = boundService.metadata.getString(KEY_EXTRA_ATTRIBUTION_TAGS);
+ if (tagsList != null) {
+ setExtraAttributionTags(
+ new ArraySet<>(tagsList.split(EXTRA_ATTRIBUTION_TAGS_SEPARATOR)));
+ }
+ }
+
provider.setLocationProviderManager(mProxy);
ProviderRequest request = mRequest;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 2dd5448..43c7365 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -479,8 +479,8 @@
return KeyStore.getInstance();
}
- public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
- return RecoverableKeyStoreManager.getInstance(mContext, keyStore);
+ public RecoverableKeyStoreManager getRecoverableKeyStoreManager() {
+ return RecoverableKeyStoreManager.getInstance(mContext);
}
public IStorageManager getStorageManager() {
@@ -561,7 +561,7 @@
mInjector = injector;
mContext = injector.getContext();
mKeyStore = injector.getKeyStore();
- mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
+ mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager();
mHandler = injector.getHandler(injector.getServiceThread());
mStrongAuth = injector.getStrongAuth();
mActivityManager = injector.getActivityManager();
diff --git a/services/core/java/com/android/server/locksettings/OWNERS b/services/core/java/com/android/server/locksettings/OWNERS
index 08b8a8c..7577ee5 100644
--- a/services/core/java/com/android/server/locksettings/OWNERS
+++ b/services/core/java/com/android/server/locksettings/OWNERS
@@ -1,3 +1,4 @@
jaggies@google.com
kchyn@google.com
rubinxu@google.com
+xunchang@google.com
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
index b3b4546..697bf08 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -44,7 +44,7 @@
* Use the default lifetime of 10 minutes. The lifetime covers the following activities:
* Server wrap secret -> device reboot -> server unwrap blob.
*/
- private static final long DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS = 600_1000;
+ private static final long DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS = 600_000;
private final LockSettingsStorage mStorage;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
index 9857fb6..f594136 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
@@ -16,8 +16,6 @@
package com.android.server.locksettings.recoverablekeystore;
-import android.security.keystore2.AndroidKeyStoreProvider;
-
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
@@ -31,24 +29,11 @@
*/
public class KeyStoreProxyImpl implements KeyStoreProxy {
+ public static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+
private final KeyStore mKeyStore;
/**
- * TODO This function redirects keystore access to the legacy keystore during a transitional
- * phase during which not all calling code has been adjusted to use Keystore 2.0.
- * This can be reverted to a constant of "AndroidKeyStore" when b/171305684 is complete.
- * The specific bug for this component is b/171305545.
- */
- static String androidKeystoreProviderName() {
- if (AndroidKeyStoreProvider.isInstalled()) {
- return "AndroidKeyStoreLegacy";
- } else {
- return "AndroidKeyStore";
- }
-
- }
-
- /**
* A new instance, delegating to {@code keyStore}.
*/
public KeyStoreProxyImpl(KeyStore keyStore) {
@@ -84,7 +69,7 @@
* @throws KeyStoreException if there was a problem getting or initializing the key store.
*/
public static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException {
- KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
+ KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
try {
keyStore.load(/*param=*/ null);
} catch (CertificateException | IOException | NoSuchAlgorithmException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index dff1df7..f448a6e 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -470,7 +470,7 @@
* @throws KeyStoreException if there was a problem getting or initializing the key store.
*/
private static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException {
- KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.androidKeystoreProviderName());
+ KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.ANDROID_KEY_STORE_PROVIDER);
try {
keyStore.load(/*param=*/ null);
} catch (CertificateException | IOException | NoSuchAlgorithmException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 6d97ed7..b49bced 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -34,7 +34,6 @@
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
-import android.security.KeyStore;
import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.RecoveryCertPath;
@@ -110,14 +109,14 @@
* @hide
*/
public static synchronized RecoverableKeyStoreManager
- getInstance(Context context, KeyStore keystore) {
+ getInstance(Context context) {
if (mInstance == null) {
RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context);
PlatformKeyManager platformKeyManager;
ApplicationKeyStorage applicationKeyStorage;
try {
platformKeyManager = PlatformKeyManager.getInstance(context, db);
- applicationKeyStorage = ApplicationKeyStorage.getInstance(keystore);
+ applicationKeyStorage = ApplicationKeyStorage.getInstance();
} catch (NoSuchAlgorithmException e) {
// Impossible: all algorithms must be supported by AOSP
throw new RuntimeException(e);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
index 84ddbf7..2398f56 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -21,9 +21,13 @@
import android.annotation.Nullable;
import android.os.ServiceSpecificException;
import android.security.Credentials;
+import android.security.KeyStore;
+import android.security.KeyStore2;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
-import android.security.KeyStore;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyPermission;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -47,32 +51,37 @@
private static final String APPLICATION_KEY_ALIAS_PREFIX =
"com.android.server.locksettings.recoverablekeystore/application/";
+ private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:";
private final KeyStoreProxy mKeyStore;
- private final KeyStore mKeystoreService;
- public static ApplicationKeyStorage getInstance(KeyStore keystoreService)
+ /**
+ * Creates a new instance.
+ */
+ public static ApplicationKeyStorage getInstance()
throws KeyStoreException {
return new ApplicationKeyStorage(
- new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()),
- keystoreService);
+ new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()));
}
@VisibleForTesting
- ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService) {
+ ApplicationKeyStorage(KeyStoreProxy keyStore) {
mKeyStore = keyStore;
- mKeystoreService = keystoreService;
}
/**
- * Returns grant alias, valid in Applications namespace.
+ * Returns String representation of {@code KeyDescriptor} valid in application's namespace.
*/
public @Nullable String getGrantAlias(int userId, int uid, String alias) {
- // Aliases used by {@link KeyStore} are different than used by public API.
- // {@code USER_PRIVATE_KEY} prefix is used secret keys.
Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias));
- String keystoreAlias = Credentials.USER_PRIVATE_KEY + getInternalAlias(userId, uid, alias);
- return mKeystoreService.grant(keystoreAlias, uid);
+ String keystoreAlias = getInternalAlias(userId, uid, alias);
+ if (useKeyStore2()) {
+ return makeKeystoreEngineGrantString(uid, keystoreAlias);
+ } else {
+ // Aliases used by {@link KeyStore} are different than used by public API.
+ // {@code USER_PRIVATE_KEY} prefix is used secret keys.
+ return KeyStore.getInstance().grant(Credentials.USER_PRIVATE_KEY + keystoreAlias, uid);
+ }
}
public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
@@ -117,4 +126,31 @@
private String getInternalAlias(int userId, int uid, String alias) {
return APPLICATION_KEY_ALIAS_PREFIX + userId + "/" + uid + "/" + alias;
}
+
+ private String makeKeystoreEngineGrantString(int uid, String alias) {
+ if (alias == null) {
+ return null;
+ }
+
+ KeyDescriptor key = new KeyDescriptor();
+ key.domain = Domain.APP;
+ key.nspace = KeyProperties.NAMESPACE_APPLICATION;
+ key.alias = alias;
+ key.blob = null;
+
+ int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO | KeyPermission.DELETE;
+
+ try {
+ key = KeyStore2.getInstance().grant(key, uid, grantAccessVector);
+ } catch (android.security.KeyStoreException e) {
+ Log.e(TAG, "Failed to get grant for KeyStore key.", e);
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ }
+ return String.format("%s%016X", APPLICATION_KEY_GRANT_PREFIX, key.nspace);
+ }
+
+ private static boolean useKeyStore2() {
+ return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
+ }
+
}
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 87e170a..cb0a6688 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -29,6 +29,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Handler;
+import android.os.PowerWhitelistManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -195,8 +196,9 @@
mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName);
final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.setTemporaryAppWhitelistDuration(
- FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS);
+ options.setTemporaryAppAllowlist(FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS,
+ PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ PowerWhitelistManager.REASON_MEDIA_BUTTON, "");
if (mPendingIntent != null) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent "
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 18f2d84..23d8429 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -40,10 +40,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
import android.media.IRemoteSessionCallback;
+import android.media.MediaCommunicationManager;
import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.IOnMediaKeyEventDispatchedListener;
@@ -151,6 +151,25 @@
private MediaSessionPolicyProvider mCustomMediaSessionPolicyProvider;
private MediaKeyDispatcher mCustomMediaKeyDispatcher;
+ private MediaCommunicationManager mCommunicationManager;
+ private final MediaCommunicationManager.SessionCallback mSession2TokenCallback =
+ new MediaCommunicationManager.SessionCallback() {
+ @Override
+ public void onSession2TokenCreated(Session2Token token) {
+ if (DEBUG) {
+ Log.d(TAG, "Session2 is created " + token);
+ }
+ MediaSession2Record record = new MediaSession2Record(token,
+ MediaSessionService.this, mRecordThread.getLooper(), 0);
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ if (user != null) {
+ user.mPriorityStack.addSession(record);
+ }
+ }
+ }
+ };
+
public MediaSessionService(Context context) {
super(context);
mContext = context;
@@ -202,6 +221,19 @@
mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter);
}
+ @Override
+ public void onBootPhase(int phase) {
+ super.onBootPhase(phase);
+ switch (phase) {
+ // This ensures MediaCommunicationService is started
+ case PHASE_BOOT_COMPLETED:
+ mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
+ mCommunicationManager.registerSessionCallback(new HandlerExecutor(mHandler),
+ mSession2TokenCallback);
+ break;
+ }
+ }
+
private final BroadcastReceiver mNotificationListenerEnabledChangedReceiver =
new BroadcastReceiver() {
@Override
@@ -1139,31 +1171,6 @@
}
@Override
- public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- if (DEBUG) {
- Log.d(TAG, "Session2 is created " + sessionToken);
- }
- if (uid != sessionToken.getUid()) {
- throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
- + " but actually=" + sessionToken.getUid());
- }
- MediaSession2Record record = new MediaSession2Record(sessionToken,
- MediaSessionService.this, mRecordThread.getLooper(), 0);
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- user.mPriorityStack.addSession(record);
- }
- // Do not immediately notify changes -- do so when framework can dispatch command
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
public List<MediaSession.Token> getSessions(ComponentName componentName, int userId) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -1185,26 +1192,6 @@
}
@Override
- public ParceledListSlice getSession2Tokens(int userId) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- try {
- // Check that they can make calls on behalf of the user and get the final user id
- int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
- List<Session2Token> result;
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(userId);
- result = user.mPriorityStack.getSession2Tokens(resolvedUserId);
- }
- return new ParceledListSlice(result);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
public void addSessionsListener(IActiveSessionsListener listener,
ComponentName componentName, int userId) throws RemoteException {
final int pid = Binder.getCallingPid();
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index bce8069..22ed781 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -40,6 +40,7 @@
private static final int VERSION_ADD_NETWORK_ID = 3;
private static final int VERSION_ADD_METERED = 4;
private static final int VERSION_ADD_DEFAULT_NETWORK = 5;
+ private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6;
public NetworkIdentitySet() {
}
@@ -84,13 +85,20 @@
defaultNetwork = true;
}
+ final int oemNetCapabilities;
+ if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) {
+ oemNetCapabilities = in.readInt();
+ } else {
+ oemNetCapabilities = NetworkIdentity.OEM_NONE;
+ }
+
add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
- defaultNetwork));
+ defaultNetwork, oemNetCapabilities));
}
}
public void writeToStream(DataOutput out) throws IOException {
- out.writeInt(VERSION_ADD_DEFAULT_NETWORK);
+ out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK);
out.writeInt(size());
for (NetworkIdentity ident : this) {
out.writeInt(ident.getType());
@@ -100,6 +108,7 @@
out.writeBoolean(ident.getRoaming());
out.writeBoolean(ident.getMetered());
out.writeBoolean(ident.getDefaultNetwork());
+ out.writeInt(ident.getOemManaged());
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2b9dd2d..067c5c0e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -54,6 +54,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkIdentity.OEM_NONE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -1404,7 +1405,11 @@
final String subscriberId = mSubIdToSubscriberId.valueAt(i);
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
- true);
+ true, OEM_NONE);
+ /* While OEM_NONE indicates "any non OEM managed network", OEM_NONE is meant to be a
+ * placeholder value here. The probeIdent is matched against a NetworkTemplate which
+ * should have its OEM managed value set to OEM_MANAGED_ALL, which will cause the
+ * template to match probeIdent without regard to OEM managed status. */
if (template.matches(probeIdent)) {
return subId;
}
@@ -1634,7 +1639,8 @@
// find and update the mobile NetworkPolicy for this subscriber id
boolean policyUpdated = false;
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true);
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true,
+ OEM_NONE);
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkTemplate template = mNetworkPolicy.keyAt(i);
if (template.matches(probeIdent)) {
@@ -1863,7 +1869,7 @@
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
- true);
+ true, OEM_NONE);
// Template is matched when subscriber id matches.
if (template.matches(probeIdent)) {
matchingSubIds.add(subId);
@@ -2178,7 +2184,8 @@
private boolean ensureActiveMobilePolicyAL(int subId, String subscriberId) {
// Poke around to see if we already have a policy
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true);
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true,
+ OEM_NONE);
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkTemplate template = mNetworkPolicy.keyAt(i);
if (template.matches(probeIdent)) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 6aefe41..557fa89 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -54,6 +54,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastDataInput;
+import com.android.internal.util.FastDataOutput;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
@@ -89,6 +91,9 @@
/** File header magic number: "ANET" */
private static final int FILE_MAGIC = 0x414E4554;
+ /** Default buffer size from BufferedInputStream */
+ private static final int BUFFER_SIZE = 8192;
+
private static final int VERSION_NETWORK_INIT = 1;
private static final int VERSION_UID_INIT = 1;
@@ -434,7 +439,8 @@
@Override
public void read(InputStream in) throws IOException {
- read((DataInput) new DataInputStream(in));
+ final FastDataInput dataIn = new FastDataInput(in, BUFFER_SIZE);
+ read(dataIn);
}
private void read(DataInput in) throws IOException {
@@ -473,8 +479,9 @@
@Override
public void write(OutputStream out) throws IOException {
- write((DataOutput) new DataOutputStream(out));
- out.flush();
+ final FastDataOutput dataOut = new FastDataOutput(out, BUFFER_SIZE);
+ write(dataOut);
+ dataOut.flush();
}
private void write(DataOutput out) throws IOException {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 9706bce..5b9a11b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1319,7 +1319,7 @@
NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
ident.getRoaming(), true /* metered */,
- true /* onDefaultNetwork */);
+ true /* onDefaultNetwork */, ident.getOemManaged());
findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f8cb2e4..73db705 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -64,6 +64,8 @@
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -73,6 +75,8 @@
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
+import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES;
+import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
@@ -6001,10 +6005,11 @@
for (int i = 0; i < intentCount; i++) {
PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
if (pendingIntent != null) {
- am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
+ am.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
ALLOWLIST_TOKEN, duration,
- BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED
- );
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_NOTIFICATION_SERVICE,
+ "NotificationManagerService");
am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
| FLAG_SERVICE_SENDER));
@@ -9863,33 +9868,54 @@
Pair listener = Pair.create(si.getComponentName(), userId);
NotificationListenerFilter existingNlf =
mRequestedNotificationListeners.get(listener);
- if (existingNlf == null) {
- // no stored filters for this listener; see if they provided a default
- if (si.metaData != null) {
- String typeList = si.metaData.getString(
- NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES);
- if (typeList != null) {
- int types = 0;
- String[] typeStrings = typeList.split(XML_SEPARATOR);
- for (int i = 0; i < typeStrings.length; i++) {
- if (TextUtils.isEmpty(typeStrings[i])) {
- continue;
- }
- try {
- types |= Integer.parseInt(typeStrings[i]);
- } catch (NumberFormatException e) {
- // skip
- }
+ if (si.metaData != null) {
+ if (existingNlf == null) {
+ // no stored filters for this listener; see if they provided a default
+ if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) {
+ String typeList =
+ si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString();
+ if (typeList != null) {
+ int types = getTypesFromStringList(typeList);
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(types, new ArraySet<>());
+ mRequestedNotificationListeners.put(listener, nlf);
}
+ }
+ }
- NotificationListenerFilter nlf =
- new NotificationListenerFilter(types, new ArraySet<>());
+ // also check the types they never want bridged
+ if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) {
+ int neverBridge = getTypesFromStringList(si.metaData.get(
+ META_DATA_DISABLED_FILTER_TYPES).toString());
+ if (neverBridge != 0) {
+ NotificationListenerFilter nlf =
+ mRequestedNotificationListeners.getOrDefault(
+ listener, new NotificationListenerFilter());
+ nlf.setTypes(nlf.getTypes() & ~neverBridge);
mRequestedNotificationListeners.put(listener, nlf);
}
}
}
}
+ private int getTypesFromStringList(String typeList) {
+ int types = 0;
+ if (typeList != null) {
+ String[] typeStrings = typeList.split(XML_SEPARATOR);
+ for (int i = 0; i < typeStrings.length; i++) {
+ if (TextUtils.isEmpty(typeStrings[i])) {
+ continue;
+ }
+ try {
+ types |= Integer.parseInt(typeStrings[i]);
+ } catch (NumberFormatException e) {
+ // skip
+ }
+ }
+ }
+ return types;
+ }
+
@GuardedBy("mNotificationLock")
public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
if (trim == TRIM_LIGHT) {
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
index 380cdb1..6875b8a 100644
--- a/services/core/java/com/android/server/pm/DumpState.java
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -56,6 +56,7 @@
private boolean mTitlePrinted;
private boolean mFullPreferred;
+ private boolean mCheckIn;
private String mTargetPackageName;
@@ -118,4 +119,12 @@
public void setFullPreferred(boolean fullPreferred) {
mFullPreferred = fullPreferred;
}
+
+ public boolean isCheckIn() {
+ return mCheckIn;
+ }
+
+ public void setCheckIn(boolean checkIn) {
+ mCheckIn = checkIn;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2812830..a5e28f1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -530,14 +530,6 @@
throw new SecurityException("User restriction prevents installing");
}
- if (params.dataLoaderParams != null
- && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("You need the "
- + "com.android.permission.USE_INSTALLER_V2 permission "
- + "to use a data loader");
- }
-
// INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK
// capability; ensure if this is set as the install reason the app has one of the necessary
// signature permissions to perform the rollback.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7bf3c5c..460b2f2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3547,14 +3547,12 @@
@Override
public DataLoaderParamsParcel getDataLoaderParams() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
}
@Override
public void addFile(int location, String name, long lengthBytes, byte[] metadata,
byte[] signature) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
if (!isDataLoaderInstallation()) {
throw new IllegalStateException(
"Cannot add files to non-data loader installation session.");
@@ -3587,7 +3585,6 @@
@Override
public void removeFile(int location, String name) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
if (!isDataLoaderInstallation()) {
throw new IllegalStateException(
"Cannot add files to non-data loader installation session.");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 16966d4..e3f925a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -97,6 +97,10 @@
import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
+import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
@@ -270,6 +274,7 @@
import android.os.ParcelableException;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
+import android.os.PowerWhitelistManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -1961,9 +1966,10 @@
boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId, int callingUid);
boolean isInstantAppResolutionAllowed(Intent intent, List<ResolveInfo> resolvedActivities,
- int userId, boolean skipPackageCheck);
+ int userId, boolean skipPackageCheck, int flags);
boolean isInstantAppResolutionAllowedBody(Intent intent,
- List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck);
+ List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
+ int flags);
boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
String resolvedType, int flags);
boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId);
@@ -2322,7 +2328,7 @@
result = filterIfNotSystemUser(mComponentResolver.queryActivities(
intent, resolvedType, flags, userId), userId);
addInstant = isInstantAppResolutionAllowed(intent, result, userId,
- false /*skipPackageCheck*/);
+ false /*skipPackageCheck*/, flags);
// Check for cross profile results.
boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
xpResolveInfo = queryCrossProfileIntents(
@@ -2387,8 +2393,8 @@
if (result == null || result.size() == 0) {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
- addInstant = isInstantAppResolutionAllowed(
- intent, null /*result*/, userId, true /*skipPackageCheck*/);
+ addInstant = isInstantAppResolutionAllowed(intent, null /*result*/, userId,
+ true /*skipPackageCheck*/, flags);
if (result == null) {
result = new ArrayList<>();
}
@@ -2603,10 +2609,22 @@
final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
+ // Blocking instant apps is usually done in applyPostResolutionFilter, but since
+ // domain verification can resolve to a single result, which can be an instant app,
+ // it will then be filtered to an empty list in that method. Instead, do blocking
+ // here so that instant apps can be ignored for approval filtering and a lower
+ // priority result chosen instead.
+ final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
+
final int count = candidates.size();
// First, try to use approved apps.
for (int n = 0; n < count; n++) {
ResolveInfo info = candidates.get(n);
+ if (blockInstant && (info.isInstantAppAvailable
+ || isInstantApp(info.activityInfo.packageName, userId))) {
+ continue;
+ }
+
// Add to the special match all list (Browser use case)
if (info.handleAllWebDataURI) {
matchAllList.add(info);
@@ -2618,7 +2636,8 @@
// We'll want to include browser possibilities in a few cases
boolean includeBrowser = false;
- if (!DomainVerificationUtils.isDomainVerificationIntent(intent)) {
+ if (!DomainVerificationUtils.isDomainVerificationIntent(intent, candidates,
+ matchFlags)) {
result.addAll(undefinedList);
// Maybe add one for the other profile.
if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
@@ -2802,8 +2821,8 @@
}
result.highestApprovalLevel = Math.max(mDomainVerificationManager
- .approvalLevelForDomain(ps, intent, riTargetUser.targetUserId),
- result.highestApprovalLevel);
+ .approvalLevelForDomain(ps, intent, resultTargetUser, flags,
+ riTargetUser.targetUserId), result.highestApprovalLevel);
}
if (result != null && result.highestApprovalLevel
<= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
@@ -3050,7 +3069,7 @@
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps.getInstantApp(userId)) {
if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
- userId)) {
+ instantApps, flags, userId)) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "Instant app approved for intent; pkg: "
+ packageName);
@@ -3928,7 +3947,7 @@
public boolean isInstantAppResolutionAllowed(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
- boolean skipPackageCheck) {
+ boolean skipPackageCheck, int flags) {
if (mInstantAppResolverConnection == null) {
return false;
}
@@ -3961,14 +3980,14 @@
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
- skipPackageCheck);
+ skipPackageCheck, flags);
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
public boolean isInstantAppResolutionAllowedBody(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
- boolean skipPackageCheck) {
+ boolean skipPackageCheck, int flags) {
final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
for (int n = 0; n < count; n++) {
final ResolveInfo info = resolvedActivities.get(n);
@@ -3978,7 +3997,7 @@
// only check domain verification status if the app is not a browser
if (!info.handleAllWebDataURI) {
if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
- userId)) {
+ resolvedActivities, flags, userId)) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
+ ", approved");
@@ -4403,6 +4422,7 @@
public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
final String packageName = dumpState.getTargetPackageName();
+ final boolean checkin = dumpState.isCheckIn();
switch (type) {
case DumpState.DUMP_VERSION:
@@ -4415,6 +4435,56 @@
break;
}
+ case DumpState.DUMP_LIBS:
+ {
+ boolean printedHeader = false;
+ final int numSharedLibraries = mSharedLibraries.size();
+ for (int index = 0; index < numSharedLibraries; index++) {
+ final String libName = mSharedLibraries.keyAt(index);
+ final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+ mSharedLibraries.get(libName);
+ if (versionedLib == null) {
+ continue;
+ }
+ final int versionCount = versionedLib.size();
+ for (int i = 0; i < versionCount; i++) {
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
+ if (!checkin) {
+ if (!printedHeader) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ pw.println("Libraries:");
+ printedHeader = true;
+ }
+ pw.print(" ");
+ } else {
+ pw.print("lib,");
+ }
+ pw.print(libraryInfo.getName());
+ if (libraryInfo.isStatic()) {
+ pw.print(" version=" + libraryInfo.getLongVersion());
+ }
+ if (!checkin) {
+ pw.print(" -> ");
+ }
+ if (libraryInfo.getPath() != null) {
+ if (libraryInfo.isNative()) {
+ pw.print(" (so) ");
+ } else {
+ pw.print(" (jar) ");
+ }
+ pw.print(libraryInfo.getPath());
+ } else {
+ pw.print(" (apk) ");
+ pw.print(libraryInfo.getPackageName());
+ }
+ pw.println();
+ }
+ }
+ break;
+ }
+
case DumpState.DUMP_PREFERRED_XML:
{
pw.flush();
@@ -4565,7 +4635,7 @@
* computer engine. This is required because there are no locks taken in
* the engine itself.
*/
- private static class ComputerLocked extends ComputerEngine {
+ private static class ComputerLocked extends ComputerEngineLive {
private final Object mLock;
ComputerLocked(Snapshot args) {
@@ -4573,16 +4643,6 @@
mLock = mService.mLock;
}
- protected ComponentName resolveComponentName() {
- return mService.mResolveComponentName;
- }
- protected ActivityInfo instantAppInstallerActivity() {
- return mService.mInstantAppInstallerActivity;
- }
- protected ApplicationInfo androidApplication() {
- return mService.mAndroidApplication;
- }
-
public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
String resolvedType, int flags, int userId, int callingUid,
String instantAppPkgName) {
@@ -4676,10 +4736,11 @@
}
}
public boolean isInstantAppResolutionAllowedBody(Intent intent,
- List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck) {
+ List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
+ int flags) {
synchronized (mLock) {
return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
- skipPackageCheck);
+ skipPackageCheck, flags);
}
}
public int getPackageUidInternal(String packageName, int flags, int userId,
@@ -4711,8 +4772,9 @@
}
- // Compute read-only functions, based on live data.
- private final Computer mLiveComputer;
+ // Compute read-only functions, based on live data. This attribute may be modified multiple
+ // times during the PackageManagerService constructor but it should not be modified thereafter.
+ private Computer mLiveComputer;
// A lock-free cache for frequently called functions.
private volatile Computer mSnapshotComputer;
// If true, the snapshot is invalid (stale). The attribute is static since it may be
@@ -5039,23 +5101,12 @@
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
- final boolean grantPermissions = (args.installFlags
- & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
final boolean killApp = (args.installFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
final boolean virtualPreload = ((args.installFlags
& PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
- final String[] grantedPermissions = args.installGrantPermissions;
- final List<String> whitelistedRestrictedPermissions = ((args.installFlags
- & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
- && parentRes.pkg != null)
- ? parentRes.pkg.getRequestedPermissions()
- : args.whitelistedRestrictedPermissions;
- int autoRevokePermissionsMode = args.autoRevokePermissionsMode;
- handlePackagePostInstall(parentRes, grantPermissions,
- killApp, virtualPreload, grantedPermissions,
- whitelistedRestrictedPermissions, autoRevokePermissionsMode,
+ handlePackagePostInstall(parentRes, killApp, virtualPreload,
didRestore, args.installSource.installerPackageName, args.observer,
args.mDataLoaderType);
@@ -5334,11 +5385,8 @@
}
}
- private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
- boolean killApp, boolean virtualPreload,
- String[] grantedPermissions, List<String> allowlistedRestrictedPermissions,
- int autoRevokePermissionsMode,
- boolean launchedForRestore, String installerPackage,
+ private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
+ boolean virtualPreload, boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
@@ -5369,29 +5417,6 @@
res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
- final PermissionManagerServiceInternal.PackageInstalledParams.Builder
- permissionParamsBuilder =
- new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
- final List<String> grantedPermissionsList;
- if (grantPermissions) {
- if (grantedPermissions != null) {
- permissionParamsBuilder.setGrantedPermissions(Arrays.asList(
- grantedPermissions));
- } else {
- permissionParamsBuilder.setGrantedPermissions(
- res.pkg.getRequestedPermissions());
- }
- }
- if (allowlistedRestrictedPermissions != null) {
- permissionParamsBuilder.setAllowlistedRestrictedPermissions(
- allowlistedRestrictedPermissions);
- }
- permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
- for (final int userId : res.newUsers) {
- mPermissionManager.onPackageInstalled(res.pkg, permissionParamsBuilder.build(),
- userId);
- }
-
final String installerPackageName =
res.installerPackageName != null
? res.installerPackageName
@@ -5524,7 +5549,8 @@
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUserIds, instantUserIds,
null /*broadcastAllowList*/,
- getTemporaryAppWhitelistBroadcastOptions().toBundle());
+ getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
+ .toBundle());
} else if (launchedForRestore && !res.pkg.isSystem()) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
@@ -6367,8 +6393,9 @@
// constructor.
mSnapshotEnabled = SNAPSHOT_ENABLED;
sSnapshotCorked = true;
+ sSnapshotInvalid = true;
mLiveComputer = createLiveComputer();
- mSnapshotComputer = mLiveComputer;
+ mSnapshotComputer = null;
registerObserver();
// CHECKSTYLE:OFF IndentationCheck
@@ -7047,6 +7074,10 @@
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
SystemClock.uptimeMillis() - startTime);
}
+
+ // Rebild the live computer since some attributes have been rebuilt.
+ mLiveComputer = createLiveComputer();
+
} // synchronized (mLock)
} // synchronized (mInstallLock)
// CHECKSTYLE:ON IndentationCheck
@@ -9167,6 +9198,11 @@
*/
@Override
public String[] getPackagesForUid(int uid) {
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ enforceCrossUserOrProfilePermission(callingUid, userId,
+ /* requireFullPermission */ false,
+ /* checkShell */ false, "getPackagesForUid");
return snapshotComputer().getPackagesForUid(uid);
}
@@ -9470,20 +9506,20 @@
private boolean isInstantAppResolutionAllowed(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
- boolean skipPackageCheck) {
+ boolean skipPackageCheck, int flags) {
return liveComputer().isInstantAppResolutionAllowed(
intent, resolvedActivities, userId,
- skipPackageCheck);
+ skipPackageCheck, flags);
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
// Or if there's already an ephemeral app installed that handles the action
private boolean isInstantAppResolutionAllowedBody(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
- boolean skipPackageCheck) {
+ boolean skipPackageCheck, int flags) {
return liveComputer().isInstantAppResolutionAllowedBody(
intent, resolvedActivities, userId,
- skipPackageCheck);
+ skipPackageCheck, flags);
}
private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
@@ -9540,7 +9576,7 @@
final String packageName = ri.activityInfo.packageName;
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && hasAnyDomainApproval(mDomainVerificationManager, ps,
- intent, userId)) {
+ intent, query, flags, userId)) {
return ri;
}
}
@@ -9597,9 +9633,10 @@
*/
private static boolean hasAnyDomainApproval(
@NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting,
- @NonNull Intent intent, @UserIdInt int userId) {
- return manager.approvalLevelForDomain(pkgSetting, intent, userId)
- > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+ @NonNull Intent intent, @NonNull List<ResolveInfo> candidates,
+ @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
+ return manager.approvalLevelForDomain(pkgSetting, intent, candidates, resolveInfoFlags,
+ userId) > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
}
/**
@@ -15159,7 +15196,8 @@
lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
}
final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
- final BroadcastOptions bOptions = getTemporaryAppWhitelistBroadcastOptions();
+ 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,
@@ -17548,7 +17586,9 @@
mInjector.getLocalService(DeviceIdleInternal.class);
final long idleDuration = getVerificationTimeout();
final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.setTemporaryAppWhitelistDuration(idleDuration);
+ options.setTemporaryAppAllowlist(idleDuration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_PACKAGE_VERIFIER, "");
/*
* If any sufficient verifiers were listed in the package
@@ -17564,7 +17604,8 @@
final ComponentName verifierComponent = sufficientVerifiers.get(i);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
verifierComponent.getPackageName(), idleDuration,
- verifierUser.getIdentifier(), false, "package verifier");
+ verifierUser.getIdentifier(), false,
+ REASON_PACKAGE_VERIFIER,"package verifier");
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
@@ -17586,7 +17627,8 @@
verification.setComponent(requiredVerifierComponent);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
mRequiredVerifierPackage, idleDuration,
- verifierUser.getIdentifier(), false, "package verifier");
+ verifierUser.getIdentifier(), false,
+ REASON_PACKAGE_VERIFIER, "package verifier");
mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
/* appOp= */ AppOpsManager.OP_NONE,
@@ -18386,6 +18428,37 @@
}
mSettings.writeKernelMappingLPr(ps);
+
+ final PermissionManagerServiceInternal.PackageInstalledParams.Builder
+ permissionParamsBuilder =
+ new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
+ final boolean grantPermissions = (installArgs.installFlags
+ & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+ if (grantPermissions) {
+ final List<String> grantedPermissions =
+ installArgs.installGrantPermissions != null
+ ? Arrays.asList(installArgs.installGrantPermissions)
+ : pkg.getRequestedPermissions();
+ permissionParamsBuilder.setGrantedPermissions(grantedPermissions);
+ }
+ final boolean allowlistAllRestrictedPermissions =
+ (installArgs.installFlags
+ & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
+ final List<String> allowlistedRestrictedPermissions =
+ allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions()
+ : installArgs.whitelistedRestrictedPermissions;
+ if (allowlistedRestrictedPermissions != null) {
+ permissionParamsBuilder.setAllowlistedRestrictedPermissions(
+ allowlistedRestrictedPermissions);
+ }
+ final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode;
+ permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
+ for (int currentUserId : allUsersList) {
+ if (ps.getInstalled(currentUserId)) {
+ mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(),
+ currentUserId);
+ }
+ }
}
res.name = pkgName;
res.uid = pkg.getUid();
@@ -20906,7 +20979,7 @@
extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
removedPackage, null, null, null, null /* broadcastAllowList */,
- getTemporaryAppWhitelistBroadcastOptions().toBundle());
+ getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
if (installerPackageName != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
removedPackage, extras, 0 /*flags*/,
@@ -22614,7 +22687,7 @@
}
final Intent intent = getHomeIntent();
final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
- PackageManager.GET_META_DATA, userId);
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
intent, null, 0, resolveInfos, 0, true, false, false, userId);
final String packageName = preferredResolveInfo != null
@@ -23699,8 +23772,6 @@
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
DumpState dumpState = new DumpState();
- boolean checkin = false;
-
ArraySet<String> permissionNames = null;
int opti = 0;
@@ -23750,7 +23821,7 @@
pw.println(" <package.name>: info about given package");
return;
} else if ("--checkin".equals(opt)) {
- checkin = true;
+ dumpState.setCheckIn(true);
} else if ("--all-components".equals(opt)) {
dumpState.setOptionEnabled(DumpState.OPTION_DUMP_ALL_COMPONENTS);
} else if ("-f".equals(opt)) {
@@ -23904,6 +23975,7 @@
}
final String packageName = dumpState.getTargetPackageName();
+ final boolean checkin = dumpState.isCheckIn();
if (checkin) {
pw.println("vers,1");
}
@@ -23992,11 +24064,7 @@
}
if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
- // TODO: Move it to ComputerEngine once LongSparseArray<SharedLibraryInfo> is copied
- // in snapshot.
- synchronized (mLock) {
- dumpSharedLibrariesLPr(pw, dumpState, checkin);
- }
+ dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
@@ -24337,53 +24405,6 @@
}
}
- private void dumpSharedLibrariesLPr(PrintWriter pw, DumpState dumpState, boolean checkin) {
- boolean printedHeader = false;
- final int numSharedLibraries = mSharedLibraries.size();
- for (int index = 0; index < numSharedLibraries; index++) {
- final String libName = mSharedLibraries.keyAt(index);
- WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
- if (versionedLib == null) {
- continue;
- }
- final int versionCount = versionedLib.size();
- for (int i = 0; i < versionCount; i++) {
- SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
- if (!checkin) {
- if (!printedHeader) {
- if (dumpState.onTitlePrinted()) {
- pw.println();
- }
- pw.println("Libraries:");
- printedHeader = true;
- }
- pw.print(" ");
- } else {
- pw.print("lib,");
- }
- pw.print(libraryInfo.getName());
- if (libraryInfo.isStatic()) {
- pw.print(" version=" + libraryInfo.getLongVersion());
- }
- if (!checkin) {
- pw.print(" -> ");
- }
- if (libraryInfo.getPath() != null) {
- if (libraryInfo.isNative()) {
- pw.print(" (so) ");
- } else {
- pw.print(" (jar) ");
- }
- pw.print(libraryInfo.getPath());
- } else {
- pw.print(" (apk) ");
- pw.print(libraryInfo.getPackageName());
- }
- pw.println();
- }
- }
- }
-
// ------- apps on sdcard specific code -------
static final boolean DEBUG_SD_INSTALL = false;
@@ -26097,6 +26118,11 @@
return PackageManagerService.this.hasSigningCertificate(
packageName, certificate, CERT_INPUT_SHA256);
}
+
+ @Override
+ public boolean hasSystemFeature(String featureName, int version) {
+ return PackageManagerService.this.hasSystemFeature(featureName, version);
+ }
}
private AndroidPackage getPackage(String packageName) {
@@ -27805,7 +27831,8 @@
return result.toArray(new PerUidReadTimeouts[result.size()]);
}
- static @NonNull BroadcastOptions getTemporaryAppWhitelistBroadcastOptions() {
+ static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+ @PowerWhitelistManager.ReasonCode int reasonCode) {
long duration = 10_000;
final ActivityManagerInternal amInternal =
LocalServices.getService(ActivityManagerInternal.class);
@@ -27813,9 +27840,9 @@
duration = amInternal.getBootTimeTempAllowListDuration();
}
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
- bOptions.setTemporaryAppWhitelistDuration(
- BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- duration);
+ bOptions.setTemporaryAppAllowlist(duration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ reasonCode, "");
return bOptions;
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index a83a3f8..38e100e 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -787,6 +787,10 @@
return firstInstallTime;
}
+ public String getName() {
+ return name;
+ }
+
protected PackageSettingBase updateFrom(PackageSettingBase other) {
super.copyFrom(other);
setPath(other.getPath());
diff --git a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
index 1c5f0a7..f411c98 100644
--- a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
+++ b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
@@ -280,7 +280,8 @@
IoUtils.closeQuietly(out);
}
- shortcut.setBitmapPath(file.getAbsolutePath());
+ final String path = file.getAbsolutePath();
+ mService.postValue(shortcut, si -> si.setBitmapPath(path));
} catch (IOException | RuntimeException e) {
Slog.e(ShortcutService.TAG, "Unable to write bitmap to file", e);
@@ -295,12 +296,14 @@
Slog.d(TAG, "Saved bitmap.");
}
if (shortcut != null) {
- if (shortcut.getBitmapPath() == null) {
- removeIcon(shortcut);
- }
+ mService.postValue(shortcut, si -> {
+ if (si.getBitmapPath() == null) {
+ removeIcon(si);
+ }
- // Whatever happened, remove this flag.
- shortcut.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
+ // Whatever happened, remove this flag.
+ si.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
+ });
}
}
return true;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index bb4ec16..302e657 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -19,15 +19,22 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Person;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.PackageIdentifier;
+import android.app.appsearch.SetSchemaRequest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.LocusId;
+import android.content.pm.AppSearchPerson;
+import android.content.pm.AppSearchShortcutInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
+import android.os.Binder;
import android.os.PersistableBundle;
import android.text.format.Formatter;
import android.util.ArrayMap;
@@ -39,9 +46,11 @@
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.ShortcutService.DumpFilter;
@@ -64,8 +73,12 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
/**
@@ -155,6 +168,16 @@
private long mLastKnownForegroundElapsedTime;
+ private final Object mLock = new Object();
+
+ /**
+ * All external packages that have gained access to the shortcuts from this package
+ */
+ private final Map<String, PackageIdentifier> mPackageIdentifiers = new ArrayMap<>(0);
+
+ @GuardedBy("mLock")
+ private AppSearchSession mAppSearchSession;
+
private ShortcutPackage(ShortcutUser shortcutUser,
int packageUserId, String packageName, ShortcutPackageInfo spi) {
super(shortcutUser, packageUserId, packageName,
@@ -200,12 +223,14 @@
// - Disable if needed.
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
ShortcutInfo si = mShortcuts.valueAt(i);
- si.clearFlags(ShortcutInfo.FLAG_SHADOW);
+ mutateShortcut(si.getId(), si, shortcut -> {
+ shortcut.clearFlags(ShortcutInfo.FLAG_SHADOW);
- si.setDisabledReason(restoreBlockReason);
- if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
- si.addFlags(ShortcutInfo.FLAG_DISABLED);
- }
+ shortcut.setDisabledReason(restoreBlockReason);
+ if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+ shortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
+ }
+ });
}
// Because some launchers may not have been restored (e.g. allowBackup=false),
// we need to re-calculate the pinned shortcuts.
@@ -437,9 +462,11 @@
if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) {
changed = true;
- si.setTimestamp(now);
- si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
- si.setRank(0); // It may still be pinned, so clear the rank.
+ mutateShortcut(si.getId(), si, shortcut -> {
+ shortcut.setTimestamp(now);
+ shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+ shortcut.setRank(0); // It may still be pinned, so clear the rank.
+ });
}
}
if (changed) {
@@ -483,7 +510,7 @@
public ShortcutInfo deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
if (shortcut != null) {
- shortcut.clearFlags(ShortcutInfo.FLAG_CACHED_ALL);
+ mutateShortcut(shortcutId, null, si -> si.clearFlags(ShortcutInfo.FLAG_CACHED_ALL));
}
return deleteOrDisableWithId(
shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
@@ -504,15 +531,16 @@
overrideImmutable, ignoreInvisible, disabledReason);
// If disabled id still exists, it is pinned and we need to update the disabled message.
- final ShortcutInfo disabled = mShortcuts.get(shortcutId);
- if (disabled != null) {
- if (disabledMessage != null) {
- disabled.setDisabledMessage(disabledMessage);
- } else if (disabledMessageResId != 0) {
- disabled.setDisabledMessageResId(disabledMessageResId);
- mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
+ mutateShortcut(shortcutId, null, disabled -> {
+ if (disabled != null) {
+ if (disabledMessage != null) {
+ disabled.setDisabledMessage(disabledMessage);
+ } else if (disabledMessageResId != 0) {
+ disabled.setDisabledMessageResId(disabledMessageResId);
+ mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
+ }
}
- }
+ });
return deleted;
}
@@ -534,21 +562,23 @@
}
if (oldShortcut.isPinned() || oldShortcut.isCached()) {
- oldShortcut.setRank(0);
- oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
- if (disable) {
- oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
- // Do not overwrite the disabled reason if one is alreay set.
- if (oldShortcut.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
- oldShortcut.setDisabledReason(disabledReason);
+ mutateShortcut(oldShortcut.getId(), oldShortcut, si -> {
+ si.setRank(0);
+ si.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
+ if (disable) {
+ si.addFlags(ShortcutInfo.FLAG_DISABLED);
+ // Do not overwrite the disabled reason if one is alreay set.
+ if (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+ si.setDisabledReason(disabledReason);
+ }
}
- }
- oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
+ si.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
- // See ShortcutRequestPinProcessor.directPinShortcut().
- if (mShortcutUser.mService.isDummyMainActivity(oldShortcut.getActivity())) {
- oldShortcut.setActivity(null);
- }
+ // See ShortcutRequestPinProcessor.directPinShortcut().
+ if (mShortcutUser.mService.isDummyMainActivity(si.getActivity())) {
+ si.setActivity(null);
+ }
+ });
return null;
} else {
@@ -558,12 +588,11 @@
}
public void enableWithId(@NonNull String shortcutId) {
- final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
- if (shortcut != null) {
- ensureNotImmutable(shortcut, /*ignoreInvisible=*/ true);
- shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
- shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
- }
+ mutateShortcut(shortcutId, null, si -> {
+ ensureNotImmutable(si, /*ignoreInvisible=*/ true);
+ si.clearFlags(ShortcutInfo.FLAG_DISABLED);
+ si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+ });
}
public void updateInvisibleShortcutForPinRequestWith(@NonNull ShortcutInfo shortcut) {
@@ -586,22 +615,25 @@
* <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
*/
public void refreshPinnedFlags() {
- // First, un-pin all shortcuts
- for (int i = mShortcuts.size() - 1; i >= 0; i--) {
- mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
+ // TODO: rewrite this function with proper query (i.e. fetch only pinned shortcuts and
+ // unpin if it's no longer pinned by any launcher and vice versa)
+ final List<ShortcutInfo> shortcuts = new ArrayList<>(mShortcuts.values());
+ final Map<String, ShortcutInfo> shortcutMap = new ArrayMap<>(shortcuts.size());
+ for (ShortcutInfo si : shortcuts) {
+ shortcutMap.put(si.getId(), si);
}
+ final Set<String> pinnedShortcuts = new ArraySet<>();
- // Then, for the pinned set for each launcher, set the pin flag one by one.
+ // First, for the pinned set for each launcher, keep track of their id one by one.
mShortcutUser.forAllLaunchers(launcherShortcuts -> {
final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
getPackageName(), getPackageUserId());
-
if (pinned == null || pinned.size() == 0) {
return;
}
for (int i = pinned.size() - 1; i >= 0; i--) {
final String id = pinned.valueAt(i);
- final ShortcutInfo si = mShortcuts.get(id);
+ final ShortcutInfo si = shortcutMap.get(id);
if (si == null) {
// This happens if a launcher pinned shortcuts from this package, then backup&
// restored, but this package doesn't allow backing up.
@@ -609,9 +641,21 @@
// That's fine, when the launcher is restored, we'll fix it.
continue;
}
- si.addFlags(ShortcutInfo.FLAG_PINNED);
+ pinnedShortcuts.add(si.getId());
}
});
+ // Then, update the pinned state if necessary
+ for (int i = shortcuts.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = shortcuts.get(i);
+ if (pinnedShortcuts.contains(si.getId()) && !si.isPinned()) {
+ mutateShortcut(si.getId(), si,
+ shortcut -> shortcut.addFlags(ShortcutInfo.FLAG_PINNED));
+ }
+ if (!pinnedShortcuts.contains(si.getId()) && si.isPinned()) {
+ mutateShortcut(si.getId(), si, shortcut ->
+ shortcut.clearFlags(ShortcutInfo.FLAG_PINNED));
+ }
+ }
// Lastly, remove the ones that are no longer pinned, cached nor dynamic.
removeOrphans();
@@ -1011,8 +1055,10 @@
continue;
}
Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId()));
- si.clearFlags(ShortcutInfo.FLAG_DISABLED);
- si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+ mutateShortcut(si.getId(), si, shortcut -> {
+ shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
+ shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+ });
}
// For existing shortcuts, update timestamps if they have any resources.
@@ -1042,21 +1088,24 @@
}
if (si.hasAnyResources()) {
- if (!si.isOriginallyFromManifest()) {
+ if (publisherRes == null) {
+ publisherRes = getPackageResources();
if (publisherRes == null) {
- publisherRes = getPackageResources();
- if (publisherRes == null) {
- break; // Resources couldn't be loaded.
- }
+ break; // Resources couldn't be loaded.
+ }
+ }
+
+ final Resources res = publisherRes;
+ mutateShortcut(si.getId(), si, shortcut -> {
+ if (!shortcut.isOriginallyFromManifest()) {
+ shortcut.lookupAndFillInResourceIds(res);
}
- // TODO: update resource strings in AppSearch
// If this shortcut is not from a manifest, then update all resource IDs
// from resource names. (We don't allow resource strings for
// non-manifest at the moment, but icons can still be resources.)
- si.lookupAndFillInResourceIds(publisherRes);
- }
- si.setTimestamp(s.injectCurrentTimeMillis());
+ shortcut.setTimestamp(s.injectCurrentTimeMillis());
+ });
}
}
}
@@ -1359,8 +1408,11 @@
}
}
- si.resolveResourceStrings(publisherRes);
- si.setTimestamp(s.injectCurrentTimeMillis());
+ final Resources res = publisherRes;
+ mutateShortcut(si.getId(), si, shortcut -> {
+ shortcut.resolveResourceStrings(res);
+ shortcut.setTimestamp(s.injectCurrentTimeMillis());
+ });
if (changedShortcuts == null) {
changedShortcuts = new ArrayList<>(1);
@@ -1377,7 +1429,7 @@
public void clearAllImplicitRanks() {
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
- si.clearImplicitRankAndRankChangedFlag();
+ mutateShortcut(si.getId(), si, ShortcutInfo::clearImplicitRankAndRankChangedFlag);
}
}
@@ -1422,8 +1474,10 @@
final ShortcutInfo si = mShortcuts.valueAt(i);
if (si.isFloating()) {
if (si.getRank() != 0) {
- si.setTimestamp(now);
- si.setRank(0);
+ mutateShortcut(si.getId(), si, shortcut -> {
+ shortcut.setTimestamp(now);
+ shortcut.setRank(0);
+ });
}
}
}
@@ -1456,8 +1510,10 @@
}
final int thisRank = rank++;
if (si.getRank() != thisRank) {
- si.setTimestamp(now);
- si.setRank(thisRank);
+ mutateShortcut(si.getId(), si, shortcut -> {
+ shortcut.setTimestamp(now);
+ shortcut.setRank(thisRank);
+ });
}
}
}
@@ -2140,6 +2196,41 @@
}
}
+ void updateVisibility(String packageName, byte[] certificate, boolean visible) {
+ if (visible) {
+ mPackageIdentifiers.put(packageName, new PackageIdentifier(packageName, certificate));
+ } else {
+ mPackageIdentifiers.remove(packageName);
+ }
+ resetAppSearch(null);
+ }
+
+ void mutateShortcut(@NonNull final String id, @Nullable final ShortcutInfo shortcut,
+ @NonNull final Consumer<ShortcutInfo> transform) {
+ Objects.requireNonNull(id);
+ Objects.requireNonNull(transform);
+ synchronized (mLock) {
+ if (shortcut != null) {
+ transform.accept(shortcut);
+ } else {
+ transform.accept(findShortcutById(id));
+ }
+ // TODO: Load ShortcutInfo from AppSearch, apply transformation logic and save
+ }
+ }
+
+ /**
+ * Removes shortcuts from AppSearch.
+ */
+ void removeShortcuts() {
+ }
+
+ /**
+ * Merge/replace shortcuts parsed from xml file.
+ */
+ void restoreParsedShortcuts(final boolean replace) {
+ }
+
private boolean verifyRanksSequential(List<ShortcutInfo> list) {
boolean failed = false;
@@ -2153,4 +2244,128 @@
}
return failed;
}
+
+ private void runInAppSearch(
+ Function<SearchSessionObservable, Consumer<AppSearchSession>>... observers) {
+ if (mShortcutUser == null) {
+ Slog.w(TAG, "shortcut user is null");
+ return;
+ }
+ synchronized (mLock) {
+ if (mAppSearchSession != null) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ final SearchSessionObservable upstream =
+ new SearchSessionObservable(mAppSearchSession, latch);
+ for (Function<SearchSessionObservable, Consumer<AppSearchSession>> observer
+ : observers) {
+ upstream.map(observer);
+ }
+ upstream.next();
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ ConcurrentUtils.waitForCountDownNoInterrupt(latch, 500,
+ "timeout accessing shortcut");
+ } else {
+ resetAppSearch(observers);
+ }
+ }
+ }
+
+ private void resetAppSearch(
+ Function<SearchSessionObservable, Consumer<AppSearchSession>>... observers) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AppSearchManager.SearchContext searchContext =
+ new AppSearchManager.SearchContext.Builder()
+ .setDatabaseName(getPackageName()).build();
+ mShortcutUser.runInAppSearch(searchContext, result -> {
+ if (!result.isSuccess()) {
+ Slog.e(TAG, "error getting search session during lazy init, "
+ + result.getErrorMessage());
+ latch.countDown();
+ return;
+ }
+ // TODO: Flatten callback chain with proper async framework
+ final SearchSessionObservable upstream =
+ new SearchSessionObservable(result.getResultValue(), latch)
+ .map(this::setupSchema);
+ if (observers != null) {
+ for (Function<SearchSessionObservable, Consumer<AppSearchSession>> observer
+ : observers) {
+ upstream.map(observer);
+ }
+ }
+ upstream.map(observable -> session -> {
+ mAppSearchSession = session;
+ observable.next();
+ });
+ upstream.next();
+ });
+ ConcurrentUtils.waitForCountDownNoInterrupt(latch, 1500,
+ "timeout accessing shortcut during lazy initialization");
+ }
+
+ /**
+ * creates the schema for shortcut in the database
+ */
+ private Consumer<AppSearchSession> setupSchema(SearchSessionObservable observable) {
+ return session -> {
+ SetSchemaRequest.Builder schemaBuilder = new SetSchemaRequest.Builder()
+ .addSchemas(AppSearchPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA);
+ for (PackageIdentifier pi : mPackageIdentifiers.values()) {
+ schemaBuilder = schemaBuilder
+ .setSchemaTypeVisibilityForPackage(
+ AppSearchPerson.SCHEMA_TYPE, true, pi)
+ .setSchemaTypeVisibilityForPackage(
+ AppSearchShortcutInfo.SCHEMA_TYPE, true, pi);
+ }
+ session.setSchema(schemaBuilder.build(), mShortcutUser.mExecutor, result -> {
+ if (!result.isSuccess()) {
+ observable.error("failed to instantiate app search schema: "
+ + result.getErrorMessage());
+ return;
+ }
+ observable.next();
+ });
+ };
+ }
+
+ /**
+ * TODO: Replace this temporary implementation with proper async framework
+ */
+ private class SearchSessionObservable {
+
+ final AppSearchSession mSession;
+ final CountDownLatch mLatch;
+ final ArrayList<Consumer<AppSearchSession>> mObservers = new ArrayList<>(1);
+
+ SearchSessionObservable(@NonNull final AppSearchSession session,
+ @NonNull final CountDownLatch latch) {
+ mSession = session;
+ mLatch = latch;
+ }
+
+ SearchSessionObservable map(
+ Function<SearchSessionObservable, Consumer<AppSearchSession>> observer) {
+ mObservers.add(observer.apply(this));
+ return this;
+ }
+
+ void next() {
+ if (mObservers.isEmpty()) {
+ mLatch.countDown();
+ return;
+ }
+ mObservers.remove(0).accept(mSession);
+ }
+
+ void error(@Nullable final String errorMessage) {
+ if (errorMessage != null) {
+ Slog.e(TAG, errorMessage);
+ }
+ mLatch.countDown();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 4d8abea..f84eb44 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -662,7 +662,7 @@
/** lifecycle event */
void handleUnlockUser(int userId) {
if (DEBUG) {
- Slog.d(TAG, "handleUnlockUser: user=" + userId);
+ Slog.d(TAG, "handleUnlockUser: user=" + userId);
}
synchronized (mUnlockedUsers) {
mUnlockedUsers.put(userId, true);
@@ -1179,6 +1179,14 @@
}
}
+ void postValue(@NonNull final ShortcutInfo shortcutInfo,
+ @NonNull final Consumer<ShortcutInfo> cb) {
+ final String pkg = shortcutInfo.getPackage();
+ final int userId = shortcutInfo.getUserId();
+ final String id = shortcutInfo.getId();
+ getPackageShortcutsLocked(pkg, userId).mutateShortcut(id, shortcutInfo, cb);
+ }
+
/** Return the last reset time. */
@GuardedBy("mLock")
long getLastResetTimeLocked() {
@@ -1566,7 +1574,6 @@
* resource-based strings.
*/
void fixUpShortcutResourceNamesAndValues(ShortcutInfo si) {
- // TODO: update resource names in AppSearch
final Resources publisherRes = injectGetResourcesForApplicationAsUser(
si.getPackage(), si.getUserId());
if (publisherRes != null) {
@@ -1947,7 +1954,7 @@
final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
injectBinderCallingPid(), injectBinderCallingUid());
- List<ShortcutInfo> changedShortcuts = null;
+ final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1);
synchronized (mLock) {
throwIfUserLockedL(userId);
@@ -1975,59 +1982,57 @@
final ShortcutInfo source = newShortcuts.get(i);
fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
- final ShortcutInfo target = ps.findShortcutById(source.getId());
+ ps.mutateShortcut(source.getId(), null, target -> {
+ // Invisible shortcuts can't be updated.
+ if (target == null || !target.isVisibleToPublisher()) {
+ return;
+ }
- // Invisible shortcuts can't be updated.
- if (target == null || !target.isVisibleToPublisher()) {
- continue;
- }
+ if (target.isEnabled() != source.isEnabled()) {
+ Slog.w(TAG,
+ "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
+ }
- if (target.isEnabled() != source.isEnabled()) {
- Slog.w(TAG,
- "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
- }
+ if (target.isLongLived() != source.isLongLived()) {
+ Slog.w(TAG,
+ "ShortcutInfo.longLived cannot be changed with updateShortcuts()");
+ }
- if (target.isLongLived() != source.isLongLived()) {
- Slog.w(TAG,
- "ShortcutInfo.longLived cannot be changed with updateShortcuts()");
- }
+ // When updating the rank, we need to insert between existing ranks, so set
+ // this setRankChanged, and also copy the implicit rank fo adjustRanks().
+ if (source.hasRank()) {
+ target.setRankChanged();
+ target.setImplicitRank(source.getImplicitRank());
+ }
- // When updating the rank, we need to insert between existing ranks, so set
- // this setRankChanged, and also copy the implicit rank fo adjustRanks().
- if (source.hasRank()) {
- target.setRankChanged();
- target.setImplicitRank(source.getImplicitRank());
- }
+ final boolean replacingIcon = (source.getIcon() != null);
+ if (replacingIcon) {
+ removeIconLocked(target);
+ }
- final boolean replacingIcon = (source.getIcon() != null);
- if (replacingIcon) {
- removeIconLocked(target);
- }
+ // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
+ target.copyNonNullFieldsFrom(source);
+ target.setTimestamp(injectCurrentTimeMillis());
- // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
- target.copyNonNullFieldsFrom(source);
- target.setTimestamp(injectCurrentTimeMillis());
+ if (replacingIcon) {
+ saveIconAndFixUpShortcutLocked(target);
+ }
- if (replacingIcon) {
- saveIconAndFixUpShortcutLocked(target);
- }
+ // When we're updating any resource related fields, re-extract the res names and
+ // the values.
+ if (replacingIcon || source.hasStringResources()) {
+ fixUpShortcutResourceNamesAndValues(target);
+ }
- // When we're updating any resource related fields, re-extract the res names and
- // the values.
- if (replacingIcon || source.hasStringResources()) {
- fixUpShortcutResourceNamesAndValues(target);
- }
-
- if (changedShortcuts == null) {
- changedShortcuts = new ArrayList<>(1);
- }
- changedShortcuts.add(target);
+ changedShortcuts.add(target);
+ });
}
// Lastly, adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId, changedShortcuts, null);
+ packageShortcutsChanged(packageName, userId,
+ changedShortcuts.isEmpty() ? null : changedShortcuts, null);
verifyStates();
@@ -2150,6 +2155,15 @@
}
@Override
+ public void updateShortcutVisibility(String callingPkg, String packageName, byte[] certificate,
+ boolean visible, int userId) {
+ synchronized (mLock) {
+ getPackageShortcutsForPublisherLocked(callingPkg, userId)
+ .updateVisibility(packageName, certificate, visible);
+ }
+ }
+
+ @Override
public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
IntentSender resultIntent, int userId) {
Objects.requireNonNull(shortcut);
@@ -3105,7 +3119,8 @@
if (doCache) {
if (si.isLongLived()) {
- si.addFlags(cacheFlags);
+ sp.mutateShortcut(si.getId(), si,
+ shortcut -> shortcut.addFlags(cacheFlags));
if (changedShortcuts == null) {
changedShortcuts = new ArrayList<>(1);
}
@@ -3116,7 +3131,8 @@
}
} else {
ShortcutInfo removed = null;
- si.clearFlags(cacheFlags);
+ sp.mutateShortcut(si.getId(), si, shortcut ->
+ shortcut.clearFlags(cacheFlags));
if (!si.isDynamic() && !si.isCached()) {
removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 3e3aa67..ec784d0 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -18,9 +18,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSession;
import android.content.pm.ShortcutManager;
import android.metrics.LogMaker;
+import android.os.Binder;
import android.os.FileUtils;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
@@ -32,6 +37,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.FgThread;
import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.InvalidFileFormatException;
@@ -45,6 +51,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
@@ -111,6 +118,8 @@
}
final ShortcutService mService;
+ final AppSearchManager mAppSearchManager;
+ final Executor mExecutor;
@UserIdInt
private final int mUserId;
@@ -132,6 +141,9 @@
public ShortcutUser(ShortcutService service, int userId) {
mService = service;
mUserId = userId;
+ mAppSearchManager = service.mContext.createContextAsUser(UserHandle.of(userId), 0)
+ .getSystemService(AppSearchManager.class);
+ mExecutor = FgThread.getExecutor();
}
public int getUserId() {
@@ -173,6 +185,9 @@
public ShortcutPackage removePackage(@NonNull String packageName) {
final ShortcutPackage removed = mPackages.remove(packageName);
+ if (removed != null) {
+ removed.removeShortcuts();
+ }
mService.cleanupBitmapsForPackage(mUserId, packageName);
return removed;
@@ -318,7 +333,10 @@
if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
if (isNewApp) {
- mPackages.remove(packageName);
+ final ShortcutPackage sp = mPackages.remove(packageName);
+ if (sp != null) {
+ sp.removeShortcuts();
+ }
}
}
}
@@ -442,6 +460,7 @@
case ShortcutPackage.TAG_ROOT: {
final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
s, ret, parser, fromBackup);
+ shortcuts.restoreParsedShortcuts(false);
// Don't use addShortcut(), we don't need to save the icon.
ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
@@ -476,6 +495,7 @@
final ShortcutPackage sp = ShortcutPackage.loadFromFile(s, ret, f, fromBackup);
if (sp != null) {
ret.mPackages.put(sp.getPackageName(), sp);
+ sp.restoreParsedShortcuts(false);
}
});
@@ -558,6 +578,7 @@
Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
+ " Existing non-manifeset shortcuts will be overwritten.");
}
+ sp.restoreParsedShortcuts(true);
addPackage(sp);
restoredPackages[0]++;
restoredShortcuts[0] += sp.getShortcutCount();
@@ -693,4 +714,18 @@
logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_SHORTCUT_COUNT)
.setSubtype(totalSharingShortcutCount));
}
+
+ void runInAppSearch(@NonNull final AppSearchManager.SearchContext searchContext,
+ @NonNull final Consumer<AppSearchResult<AppSearchSession>> callback) {
+ if (mAppSearchManager == null) {
+ Slog.e(TAG, "app search manager is null");
+ return;
+ }
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mAppSearchManager.createSearchSession(searchContext, mExecutor, callback);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index c17d2e4..eb2de60 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -63,8 +63,13 @@
*/
public interface UserLifecycleListener {
- /** Called when a new user is created. */
- default void onUserCreated(UserInfo user) {}
+ /**
+ * Called when a new user is created.
+ *
+ * @param user new user.
+ * @param token token passed to the method that created the user.
+ */
+ default void onUserCreated(UserInfo user, @Nullable Object token) {}
/** Called when an existing user is removed. */
default void onUserRemoved(UserInfo user) {}
@@ -179,10 +184,12 @@
* {@link UserManager#DISALLOW_ADD_USER} and {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}
*
* <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
- * createAndManageUser is called by the device owner.
+ * createAndManageUser is called by the device owner; it uses {@code token} to block until
+ * the user is created (as it will be passed back to it through
+ * {@link UserLifecycleListener#onUserCreated(UserInfo, Object)});
*/
public abstract UserInfo createUserEvenWhenDisallowed(String name, String userType,
- int flags, String[] disallowedPackages)
+ int flags, String[] disallowedPackages, @Nullable Object token)
throws UserManager.CheckedUserOperationException;
/**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 24c27be..871576e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -983,7 +983,11 @@
@Override
public UserInfo getProfileParent(@UserIdInt int userId) {
- checkManageUsersPermission("get the profile parent");
+ if (!hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ throw new SecurityException(
+ "You need MANAGE_USERS or INTERACT_ACROSS_USERS permission to get the "
+ + "profile parent");
+ }
synchronized (mUsersLock) {
return getProfileParentLU(userId);
}
@@ -1522,20 +1526,30 @@
}
@Override
- public boolean isUserForeground() {
- int callingUserId = Binder.getCallingUserHandle().getIdentifier();
+ public boolean isUserForeground(@UserIdInt int userId) {
+ final int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId != userId
+ && !hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ throw new SecurityException("Caller from user " + callingUserId + " needs MANAGE_USERS "
+ + "or INTERACT_ACROSS_USERS permission to check if another user (" + userId
+ + ") is running in the foreground");
+ }
+
int currentUser = Binder.withCleanCallingIdentity(() -> ActivityManager.getCurrentUser());
// TODO(b/179163496): should return true for profile users of the current user as well
- return currentUser == callingUserId;
+ return currentUser == userId;
}
@Override
public String getUserName() {
- if (!hasManageUsersOrPermission(android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
- throw new SecurityException("You need MANAGE_USERS or GET_ACCOUNTS_PRIVILEGED "
- + "permissions to: get user name");
+ final int callingUid = Binder.getCallingUid();
+ if (!hasManageOrCreateUsersPermission()
+ || hasPermissionGranted(
+ android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, callingUid)) {
+ throw new SecurityException("You need MANAGE_USERS or CREATE_USERS or "
+ + "GET_ACCOUNTS_PRIVILEGED permissions to: get user name");
}
- final int userId = UserHandle.getUserId(Binder.getCallingUid());
+ final int userId = UserHandle.getUserId(callingUid);
synchronized (mUsersLock) {
UserInfo userInfo = userWithName(getUserInfoLU(userId));
return userInfo == null ? "" : userInfo.name;
@@ -3287,7 +3301,7 @@
* as well as for {@link UserManager#USER_TYPE_FULL_RESTRICTED}.
*/
@Override
- public UserInfo createProfileForUserWithThrow(String name, @NonNull String userType,
+ public UserInfo createProfileForUserWithThrow(@Nullable String name, @NonNull String userType,
@UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages)
throws ServiceSpecificException {
checkManageOrCreateUsersPermission(flags);
@@ -3309,7 +3323,7 @@
checkManageOrCreateUsersPermission(flags);
try {
return createUserInternalUnchecked(name, userType, flags, userId,
- /* preCreate= */ false, disallowedPackages);
+ /* preCreate= */ false, disallowedPackages, /* token= */ null);
} catch (UserManager.CheckedUserOperationException e) {
throw e.toServiceSpecificException();
}
@@ -3342,7 +3356,7 @@
try {
return createUserInternalUnchecked(/* name= */ null, userType, flags,
/* parentId= */ UserHandle.USER_NULL, /* preCreate= */ true,
- /* disallowedPackages= */ null);
+ /* disallowedPackages= */ null, /* token= */ null);
} catch (UserManager.CheckedUserOperationException e) {
throw e.toServiceSpecificException();
}
@@ -3358,12 +3372,13 @@
enforceUserRestriction(restriction, UserHandle.getCallingUserId(),
"Cannot add user");
return createUserInternalUnchecked(name, userType, flags, parentId,
- /* preCreate= */ false, disallowedPackages);
+ /* preCreate= */ false, disallowedPackages, /* token= */ null);
}
private UserInfo createUserInternalUnchecked(@Nullable String name,
@NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
- boolean preCreate, @Nullable String[] disallowedPackages)
+ boolean preCreate, @Nullable String[] disallowedPackages,
+ @Nullable Object token)
throws UserManager.CheckedUserOperationException {
final int nextProbableUserId = getNextAvailableId();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
@@ -3372,7 +3387,7 @@
UserInfo newUser = null;
try {
newUser = createUserInternalUncheckedNoTracing(name, userType, flags, parentId,
- preCreate, disallowedPackages, t);
+ preCreate, disallowedPackages, t, token);
return newUser;
} finally {
logUserCreateJourneyFinish(sessionId, nextProbableUserId, newUser != null);
@@ -3383,7 +3398,8 @@
private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name,
@NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
boolean preCreate, @Nullable String[] disallowedPackages,
- @NonNull TimingsTraceAndSlog t) throws UserManager.CheckedUserOperationException {
+ @NonNull TimingsTraceAndSlog t, @Nullable Object token)
+ throws UserManager.CheckedUserOperationException {
final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
if (userTypeDetails == null) {
Slog.e(LOG_TAG, "Cannot create user of invalid user type: " + userType);
@@ -3409,7 +3425,8 @@
// Try to use a pre-created user (if available).
if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) {
- final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name);
+ final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name,
+ token);
if (preCreatedUser != null) {
return preCreatedUser;
}
@@ -3588,7 +3605,7 @@
Slog.w(LOG_TAG, "could not start pre-created user " + userId, e);
}
} else {
- dispatchUserAdded(userInfo);
+ dispatchUserAdded(userInfo, token);
}
} finally {
@@ -3688,7 +3705,7 @@
* @return the converted user, or {@code null} if no pre-created user could be converted.
*/
private @Nullable UserInfo convertPreCreatedUserIfPossible(String userType,
- @UserInfoFlag int flags, String name) {
+ @UserInfoFlag int flags, String name, @Nullable Object token) {
final UserData preCreatedUserData;
synchronized (mUsersLock) {
preCreatedUserData = getPreCreatedUserLU(userType);
@@ -3726,7 +3743,7 @@
}
updateUserIds();
mPm.onNewUserCreated(preCreatedUser.id, /* convertedFromPreCreated= */ true);
- dispatchUserAdded(preCreatedUser);
+ dispatchUserAdded(preCreatedUser, token);
return preCreatedUser;
}
@@ -3758,11 +3775,11 @@
return (now > EPOCH_PLUS_30_YEARS) ? now : 0;
}
- private void dispatchUserAdded(@NonNull UserInfo userInfo) {
+ private void dispatchUserAdded(@NonNull UserInfo userInfo, @Nullable Object token) {
// Notify internal listeners first...
synchronized (mUserLifecycleListeners) {
for (int i = 0; i < mUserLifecycleListeners.size(); i++) {
- mUserLifecycleListeners.get(i).onUserCreated(userInfo);
+ mUserLifecycleListeners.get(i).onUserCreated(userInfo, token);
}
}
@@ -3868,7 +3885,7 @@
* @hide
*/
@Override
- public UserInfo createRestrictedProfileWithThrow(String name, int parentUserId) {
+ public UserInfo createRestrictedProfileWithThrow(@Nullable String name, int parentUserId) {
checkManageOrCreateUsersPermission("setupRestrictedProfile");
final UserInfo user = createProfileForUserWithThrow(
name, UserManager.USER_TYPE_FULL_RESTRICTED, 0, parentUserId, null);
@@ -5367,10 +5384,10 @@
@Override
public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType,
- @UserInfoFlag int flags, String[] disallowedPackages)
+ @UserInfoFlag int flags, String[] disallowedPackages, @Nullable Object token)
throws UserManager.CheckedUserOperationException {
return createUserInternalUnchecked(name, userType, flags,
- UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages);
+ UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages, token);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 44a2187..e3ccb75 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1277,12 +1277,7 @@
newFlags |= (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
// If we are allowlisting the permission, update the exempt flag before grant.
- // If the permission can't be allowlisted by an installer, skip it here because
- // this is where the platform takes the role of the installer for exempting
- // preinstalled apps.
- if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)
- && !pm.getPermissionInfo(permission).isInstallerExemptIgnored()) {
-
+ if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)) {
pm.updatePermissionFlags(permission, pkg,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 32bee58..ac50f29 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -239,10 +239,6 @@
return (mPermissionInfo.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
}
- public boolean isInstallerExemptIgnored() {
- return (mPermissionInfo.flags & PermissionInfo.FLAG_INSTALLER_EXEMPT_IGNORED) != 0;
- }
-
public boolean isSignature() {
return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_SIGNATURE;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7a936ec..2dfb6ff 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -24,14 +24,12 @@
import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED;
import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -771,10 +769,6 @@
isRuntimePermission = bp.isRuntime();
- if (bp.isInstallerExemptIgnored()) {
- flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
- }
-
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
@@ -1018,8 +1012,7 @@
Preconditions.checkFlagsArgument(flags,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
- | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
- | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE);
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
Preconditions.checkArgumentNonNegative(userId, null);
if (UserHandle.getCallingUserId() != userId) {
@@ -1043,9 +1036,9 @@
final boolean isCallerInstallerOnRecord =
mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
- if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
- | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE)) != 0 && !isCallerPrivileged) {
- throw new SecurityException("Querying system or role allowlist requires "
+ if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+ && !isCallerPrivileged) {
+ throw new SecurityException("Querying system allowlist requires "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
@@ -1087,9 +1080,6 @@
if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
}
- if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
- queryFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- }
ArrayList<String> allowlistedPermissions = null;
@@ -1182,8 +1172,7 @@
Preconditions.checkFlagsArgument(flags,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
- | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
- | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE);
+ | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
Preconditions.checkArgument(Integer.bitCount(flags) == 1);
Preconditions.checkArgumentNonNegative(userId, null);
@@ -1209,10 +1198,8 @@
final boolean isCallerInstallerOnRecord =
mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
- if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
- | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE)) != 0
- && !isCallerPrivileged) {
- throw new SecurityException("Modifying system or role allowlist requires "
+ if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0 && !isCallerPrivileged) {
+ throw new SecurityException("Modifying system allowlist requires "
+ Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
}
@@ -3718,15 +3705,6 @@
}
}
break;
- case FLAG_PERMISSION_ALLOWLIST_ROLE: {
- mask |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- } else {
- newFlags &= ~FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- }
- }
- break;
}
}
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 080de73..bf2b3c7 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
@@ -42,6 +42,8 @@
private static final Pattern DOMAIN_NAME_WITH_WILDCARD =
Pattern.compile("(\\*\\.)?" + Patterns.DOMAIN_NAME.pattern());
+ private static final int MAX_DOMAINS_BYTE_SIZE = 1024 * 1024;
+
@NonNull
private final PlatformCompat mPlatformCompat;
@@ -71,7 +73,7 @@
* <li>- Only IntentFilter.SCHEME_HTTP and/or IntentFilter.SCHEME_HTTPS,
* with no other schemes</li>
* </ul>
- *
+ * <p>
* On prior versions of Android, Intent.CATEGORY_BROWSABLE was not a requirement, other
* schemes were allowed, and setting autoVerify to true in any intent filter would implicitly
* pretend that all intent filters were set to autoVerify="true".
@@ -82,42 +84,48 @@
@NonNull
public ArraySet<String> collectAllWebDomains(@NonNull AndroidPackage pkg) {
- return collectDomains(pkg, false);
+ return collectDomains(pkg, false /* checkAutoVerify */, true /* valid */);
}
/**
- * Effectively {@link #collectAllWebDomains(AndroidPackage)}, but requires
- * {@link IntentFilter#getAutoVerify()} == true.
+ * Effectively {@link #collectAllWebDomains(AndroidPackage)}, but requires {@link
+ * IntentFilter#getAutoVerify()} == true.
*/
@NonNull
- public ArraySet<String> collectAutoVerifyDomains(@NonNull AndroidPackage pkg) {
- return collectDomains(pkg, true);
+ public ArraySet<String> collectValidAutoVerifyDomains(@NonNull AndroidPackage pkg) {
+ return collectDomains(pkg, true /* checkAutoVerify */, true /* valid */);
+ }
+
+ /**
+ * Returns all the domains that are configured to be auto verified, but aren't actually valid
+ * HTTP domains, per {@link #DOMAIN_NAME_WITH_WILDCARD}.
+ */
+ @NonNull
+ public ArraySet<String> collectInvalidAutoVerifyDomains(@NonNull AndroidPackage pkg) {
+ return collectDomains(pkg, true /* checkAutoVerify */, false /* valid */);
}
@NonNull
private ArraySet<String> collectDomains(@NonNull AndroidPackage pkg,
- boolean checkAutoVerify) {
+ boolean checkAutoVerify, boolean valid) {
boolean restrictDomains =
DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, RESTRICT_DOMAINS);
- ArraySet<String> domains = new ArraySet<>();
-
if (restrictDomains) {
- collectDomains(domains, pkg, checkAutoVerify);
+ return collectDomainsInternal(pkg, checkAutoVerify, valid);
} else {
- collectDomainsLegacy(domains, pkg, checkAutoVerify);
+ return collectDomainsLegacy(pkg, checkAutoVerify, valid);
}
-
- return domains;
}
- /** @see #RESTRICT_DOMAINS */
- private void collectDomainsLegacy(@NonNull Set<String> domains,
- @NonNull AndroidPackage pkg, boolean checkAutoVerify) {
+ /**
+ * @see #RESTRICT_DOMAINS
+ */
+ private ArraySet<String> collectDomainsLegacy(@NonNull AndroidPackage pkg,
+ boolean checkAutoVerify, boolean valid) {
if (!checkAutoVerify) {
// Per-domain user selection state doesn't have a V1 equivalent on S, so just use V2
- collectDomains(domains, pkg, false);
- return;
+ return collectDomainsInternal(pkg, false /* checkAutoVerify */, true /* valid */);
}
List<ParsedActivity> activities = pkg.getActivities();
@@ -140,39 +148,54 @@
}
if (!needsAutoVerify) {
- return;
+ return new ArraySet<>();
}
}
- for (int activityIndex = 0; activityIndex < activitiesSize; activityIndex++) {
+ ArraySet<String> domains = new ArraySet<>();
+ int totalSize = 0;
+ boolean underMaxSize = true;
+ for (int activityIndex = 0; activityIndex < activitiesSize && underMaxSize;
+ activityIndex++) {
ParsedActivity activity = activities.get(activityIndex);
List<ParsedIntentInfo> intents = activity.getIntents();
int intentsSize = intents.size();
- for (int intentIndex = 0; intentIndex < intentsSize; intentIndex++) {
+ for (int intentIndex = 0; intentIndex < intentsSize && underMaxSize; intentIndex++) {
ParsedIntentInfo intent = intents.get(intentIndex);
if (intent.handlesWebUris(false)) {
int authorityCount = intent.countDataAuthorities();
for (int index = 0; index < authorityCount; index++) {
String host = intent.getDataAuthority(index).getHost();
- if (isValidHost(host)) {
+ if (isValidHost(host) == valid) {
+ totalSize += byteSizeOf(host);
+ underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
domains.add(host);
}
}
}
}
}
+
+ return domains;
}
- /** @see #RESTRICT_DOMAINS */
- private void collectDomains(@NonNull Set<String> domains,
- @NonNull AndroidPackage pkg, boolean checkAutoVerify) {
+ /**
+ * @see #RESTRICT_DOMAINS
+ */
+ private ArraySet<String> collectDomainsInternal(@NonNull AndroidPackage pkg,
+ boolean checkAutoVerify, boolean valid) {
+ ArraySet<String> domains = new ArraySet<>();
+ int totalSize = 0;
+ boolean underMaxSize = true;
+
List<ParsedActivity> activities = pkg.getActivities();
int activitiesSize = activities.size();
- for (int activityIndex = 0; activityIndex < activitiesSize; activityIndex++) {
+ for (int activityIndex = 0; activityIndex < activitiesSize && underMaxSize;
+ activityIndex++) {
ParsedActivity activity = activities.get(activityIndex);
List<ParsedIntentInfo> intents = activity.getIntents();
int intentsSize = intents.size();
- for (int intentIndex = 0; intentIndex < intentsSize; intentIndex++) {
+ for (int intentIndex = 0; intentIndex < intentsSize && underMaxSize; intentIndex++) {
ParsedIntentInfo intent = intents.get(intentIndex);
if (checkAutoVerify && !intent.getAutoVerify()) {
continue;
@@ -198,14 +221,27 @@
// app developer by declaring a separate intent-filter. This may not be worth
// fixing.
int authorityCount = intent.countDataAuthorities();
- for (int index = 0; index < authorityCount; index++) {
+ for (int index = 0; index < authorityCount && underMaxSize; index++) {
String host = intent.getDataAuthority(index).getHost();
- if (isValidHost(host)) {
+ if (isValidHost(host) == valid) {
+ totalSize += byteSizeOf(host);
+ underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
domains.add(host);
}
}
}
}
+
+ return domains;
+ }
+
+ /**
+ * Ballpark the size of domains to avoid a ridiculous amount of domains that could slow
+ * down client-server communication.
+ */
+ private int byteSizeOf(String string) {
+ // Use the same method from core for the data objects so that restrictions are consistent
+ return android.content.pm.verify.domain.DomainVerificationUtils.estimatedByteSizeOf(string);
}
/**
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index b3108c5..c9067a3 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -107,7 +107,7 @@
reusedMap.clear();
reusedMap.putAll(pkgState.getStateMap());
- ArraySet<String> declaredDomains = mCollector.collectAutoVerifyDomains(pkg);
+ ArraySet<String> declaredDomains = mCollector.collectValidAutoVerifyDomains(pkg);
int declaredSize = declaredDomains.size();
for (int declaredIndex = 0; declaredIndex < declaredSize; declaredIndex++) {
String domain = declaredDomains.valueAt(declaredIndex);
@@ -132,6 +132,17 @@
}
writer.increaseIndent();
+ final ArraySet<String> invalidDomains = mCollector.collectInvalidAutoVerifyDomains(pkg);
+ if (!invalidDomains.isEmpty()) {
+ writer.println("Invalid autoVerify domains:");
+ writer.increaseIndent();
+ int size = invalidDomains.size();
+ for (int index = 0; index < size; index++) {
+ writer.println(invalidDomains.valueAt(index));
+ }
+ writer.decreaseIndent();
+ }
+
writer.println("Domain verification state:");
writer.increaseIndent();
int stateSize = reusedMap.size();
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
index 275dd053..ed37fa0 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
@@ -185,6 +185,29 @@
return !mCallback.filterAppAccess(packageName, callingUid, targetUserId);
}
+ /**
+ * Querying for the owners of a domain. Because this API cannot filter the returned list of
+ * packages, enforces {@link android.Manifest.permission.QUERY_ALL_PACKAGES}, but also enforces
+ * {@link android.Manifest.permission.INTERACT_ACROSS_USERS} because each user has a different
+ * state.
+ */
+ public void assertOwnerQuerent(int callingUid, @UserIdInt int callingUserId,
+ @UserIdInt int targetUserId) {
+ final int callingPid = Binder.getCallingPid();
+ if (callingUserId != targetUserId) {
+ mContext.enforcePermission(android.Manifest.permission.INTERACT_ACROSS_USERS,
+ callingPid, callingUid, "Caller is not allowed to query other users");
+ }
+
+ mContext.enforcePermission(android.Manifest.permission.QUERY_ALL_PACKAGES,
+ callingPid, callingUid, "Caller " + callingUid + " does not hold "
+ + android.Manifest.permission.QUERY_ALL_PACKAGES);
+
+ mContext.enforcePermission(
+ android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION,
+ callingPid, callingUid, "Caller is not allowed to query user selections");
+ }
+
public interface Callback {
/**
* @return true if access to the given package should be filtered and the method failed as
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index b6ea901..a68b3da 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -310,7 +310,8 @@
*/
@ApprovalLevel
int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
- @UserIdInt int userId);
+ @NonNull List<ResolveInfo> candidates,
+ @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId);
/**
* @return the domain verification set ID for the given package, or null if the ID is
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 8aa6337..6f28107 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
@@ -20,13 +20,14 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.verify.domain.DomainOwner;
+import android.content.pm.verify.domain.DomainSet;
+import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
import android.content.pm.verify.domain.DomainVerificationManagerImpl;
-import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationUserSelection;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.ServiceSpecificException;
-import android.util.ArraySet;
import java.util.List;
import java.util.UUID;
@@ -61,11 +62,11 @@
}
@Override
- public void setDomainVerificationStatus(String domainSetId, List<String> domains,
+ public void setDomainVerificationStatus(String domainSetId, @NonNull DomainSet domainSet,
int state) {
try {
mService.setDomainVerificationStatus(UUID.fromString(domainSetId),
- new ArraySet<>(domains), state);
+ domainSet.getDomains(), state);
} catch (Exception e) {
throw rethrow(e);
}
@@ -82,11 +83,11 @@
}
@Override
- public void setDomainVerificationUserSelection(String domainSetId, List<String> domains,
+ public void setDomainVerificationUserSelection(String domainSetId, @NonNull DomainSet domainSet,
boolean enabled, @UserIdInt int userId) {
try {
mService.setDomainVerificationUserSelection(UUID.fromString(domainSetId),
- new ArraySet<>(domains), enabled, userId);
+ domainSet.getDomains(), enabled, userId);
} catch (Exception e) {
throw rethrow(e);
}
@@ -103,6 +104,17 @@
}
}
+ @Nullable
+ @Override
+ public List<DomainOwner> getOwnersForDomain(@NonNull String domain,
+ @UserIdInt int userId) {
+ try {
+ return mService.getOwnersForDomain(domain, userId);
+ } catch (Exception e) {
+ throw rethrow(e);
+ }
+ }
+
private RuntimeException rethrow(Exception exception) throws RuntimeException {
if (exception instanceof InvalidDomainSetException) {
int packedErrorCode = DomainVerificationManagerImpl.ERROR_INVALID_DOMAIN_SET;
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 8e5aead..dbd7f96 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
@@ -17,6 +17,7 @@
package com.android.server.pm.verify.domain;
import static java.util.Collections.emptyList;
+import static java.util.Collections.emptySet;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,6 +31,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.parsing.component.ParsedActivity;
+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.DomainVerificationState;
@@ -254,7 +256,7 @@
Map<String, Integer> hostToStateMap = new ArrayMap<>(pkgState.getStateMap());
// TODO(b/159952358): Should the domain list be cached?
- ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+ ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
if (domains.isEmpty()) {
return null;
}
@@ -291,6 +293,8 @@
throws InvalidDomainSetException, NameNotFoundException {
mEnforcer.assertApprovedVerifier(callingUid, mProxy);
synchronized (mLock) {
+ List<String> verifiedDomains = new ArrayList<>();
+
DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
true /* forAutoVerify */, callingUid, null /* userId */);
ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
@@ -301,8 +305,17 @@
continue;
}
+ if (DomainVerificationManager.isStateVerified(state)) {
+ verifiedDomains.add(domain);
+ }
+
stateMap.put(domain, state);
}
+
+ int size = verifiedDomains.size();
+ for (int index = 0; index < size; index++) {
+ removeUserSelectionsForDomain(verifiedDomains.get(index));
+ }
}
mConnection.scheduleWriteSettings();
@@ -341,7 +354,8 @@
validDomains.clear();
- ArraySet<String> autoVerifyDomains = mCollector.collectAutoVerifyDomains(pkg);
+ ArraySet<String> autoVerifyDomains =
+ mCollector.collectValidAutoVerifyDomains(pkg);
if (domains == null) {
validDomains.addAll(autoVerifyDomains);
} else {
@@ -366,9 +380,9 @@
AndroidPackage pkg = pkgSetting.getPkg();
if (domains == null) {
- domains = mCollector.collectAutoVerifyDomains(pkg);
+ domains = mCollector.collectValidAutoVerifyDomains(pkg);
} else {
- domains.retainAll(mCollector.collectAutoVerifyDomains(pkg));
+ domains.retainAll(mCollector.collectValidAutoVerifyDomains(pkg));
}
setDomainVerificationStatusInternal(pkgState, state, domains);
@@ -387,6 +401,20 @@
}
}
+ private void removeUserSelectionsForDomain(@NonNull String domain) {
+ synchronized (mLock) {
+ final int size = mAttachedPkgStates.size();
+ for (int index = 0; index < size; index++) {
+ DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+ SparseArray<DomainVerificationUserState> array = pkgState.getUserSelectionStates();
+ int arraySize = array.size();
+ for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) {
+ array.valueAt(arrayIndex).removeHost(domain);
+ }
+ }
+ }
+ }
+
@Override
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed) throws NameNotFoundException {
@@ -470,19 +498,59 @@
InvalidDomainSetException.REASON_ID_INVALID);
}
+ DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
+ false /* forAutoVerify */, callingUid, userId);
+ DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
+
+ // Disable other packages if approving this one. Note that this check is only done for
+ // enabling. This allows an escape hatch in case multiple packages somehow get selected.
+ // They can be disabled without blocking in a circular dependency.
if (enabled) {
+ // Cache the approved packages from the 1st pass because the search is expensive
+ ArrayMap<String, List<String>> domainToApprovedPackages = new ArrayMap<>();
+
for (String domain : domains) {
- if (!getApprovedPackages(domain, userId, APPROVAL_LEVEL_LEGACY_ALWAYS + 1,
- mConnection::getPackageSettingLocked).first.isEmpty()) {
+ if (userState.getEnabledHosts().contains(domain)) {
+ continue;
+ }
+
+ Pair<List<String>, Integer> packagesToLevel = getApprovedPackages(domain,
+ userId, APPROVAL_LEVEL_NONE + 1, mConnection::getPackageSettingLocked);
+ int highestApproval = packagesToLevel.second;
+ if (highestApproval > APPROVAL_LEVEL_SELECTION) {
throw new InvalidDomainSetException(domainSetId, null,
InvalidDomainSetException.REASON_UNABLE_TO_APPROVE);
}
+
+ domainToApprovedPackages.put(domain, packagesToLevel.first);
+ }
+
+ // The removal for other packages must be done in a 2nd pass after it's determined
+ // that no higher priority owners exist for all of the domains in the set.
+ int mapSize = domainToApprovedPackages.size();
+ for (int mapIndex = 0; mapIndex < mapSize; mapIndex++) {
+ String domain = domainToApprovedPackages.keyAt(mapIndex);
+ List<String> approvedPackages = domainToApprovedPackages.valueAt(mapIndex);
+ int approvedSize = approvedPackages.size();
+ for (int approvedIndex = 0; approvedIndex < approvedSize; approvedIndex++) {
+ String approvedPackage = approvedPackages.get(approvedIndex);
+ DomainVerificationPkgState approvedPkgState =
+ mAttachedPkgStates.get(approvedPackage);
+ if (approvedPkgState == null) {
+ continue;
+ }
+
+ DomainVerificationUserState approvedUserState =
+ approvedPkgState.getUserSelectionState(userId);
+ if (approvedUserState == null) {
+ continue;
+ }
+
+ approvedUserState.removeHost(domain);
+ }
}
}
- DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
- false /* forAutoVerify */, callingUid, userId);
- DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
if (enabled) {
userState.addHosts(domains);
} else {
@@ -600,32 +668,113 @@
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
- ArrayMap<String, Boolean> hostToUserSelectionMap = new ArrayMap<>();
+ ArraySet<String> webDomains = mCollector.collectAllWebDomains(pkg);
+ int webDomainsSize = webDomains.size();
- ArraySet<String> domains = mCollector.collectAllWebDomains(pkg);
- int domainsSize = domains.size();
- for (int index = 0; index < domainsSize; index++) {
- hostToUserSelectionMap.put(domains.valueAt(index), false);
- }
-
+ Map<String, Integer> domains = new ArrayMap<>(webDomainsSize);
+ ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
- boolean linkHandlingAllowed = true;
- if (userState != null) {
- linkHandlingAllowed = userState.isLinkHandlingAllowed();
- ArraySet<String> enabledHosts = userState.getEnabledHosts();
- int hostsSize = enabledHosts.size();
- for (int index = 0; index < hostsSize; index++) {
- hostToUserSelectionMap.put(enabledHosts.valueAt(index), true);
+ Set<String> enabledHosts = userState == null ? emptySet() : userState.getEnabledHosts();
+
+ for (int index = 0; index < webDomainsSize; index++) {
+ String host = webDomains.valueAt(index);
+ Integer state = stateMap.get(host);
+
+ int domainState;
+ if (state != null && DomainVerificationManager.isStateVerified(state)) {
+ domainState = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED;
+ } else if (enabledHosts.contains(host)) {
+ domainState = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED;
+ } else {
+ domainState = DomainVerificationUserSelection.DOMAIN_STATE_NONE;
}
+
+ domains.put(host, domainState);
}
+ boolean linkHandlingAllowed = userState == null || userState.isLinkHandlingAllowed();
+
return new DomainVerificationUserSelection(pkgState.getId(), packageName,
- UserHandle.of(userId), linkHandlingAllowed, hostToUserSelectionMap);
+ UserHandle.of(userId), linkHandlingAllowed, domains);
}
}
@NonNull
@Override
+ public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
+ return getOwnersForDomain(domain, mConnection.getCallingUserId());
+ }
+
+ public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
+ mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
+ userId);
+
+ SparseArray<List<String>> levelToPackages = new SparseArray<>();
+
+ // First, collect the raw approval level values
+ synchronized (mLock) {
+ final int size = mAttachedPkgStates.size();
+ for (int index = 0; index < size; index++) {
+ DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+ String packageName = pkgState.getPackageName();
+ PackageSetting pkgSetting = mConnection.getPackageSettingLocked(packageName);
+ if (pkgSetting == null) {
+ continue;
+ }
+
+ int level = approvalLevelForDomain(pkgSetting, domain, userId, domain);
+ if (level <= APPROVAL_LEVEL_NONE) {
+ continue;
+ }
+ List<String> list = levelToPackages.get(level);
+ if (list == null) {
+ list = new ArrayList<>();
+ levelToPackages.put(level, list);
+ }
+ list.add(packageName);
+ }
+ }
+
+ final int size = levelToPackages.size();
+ if (size == 0) {
+ return emptyList();
+ }
+
+ // Then sort them ascending by first installed time, with package name as the tie breaker
+ for (int index = 0; index < size; index++) {
+ levelToPackages.valueAt(index).sort((first, second) -> {
+ PackageSetting firstPkgSetting = mConnection.getPackageSettingLocked(first);
+ PackageSetting secondPkgSetting = mConnection.getPackageSettingLocked(second);
+
+ long firstInstallTime =
+ firstPkgSetting == null ? -1L : firstPkgSetting.getFirstInstallTime();
+ long secondInstallTime =
+ secondPkgSetting == null ? -1L : secondPkgSetting.getFirstInstallTime();
+
+ if (firstInstallTime != secondInstallTime) {
+ return (int) (firstInstallTime - secondInstallTime);
+ }
+
+ return first.compareToIgnoreCase(second);
+ });
+ }
+
+ List<DomainOwner> owners = new ArrayList<>();
+ for (int index = 0; index < size; index++) {
+ int level = levelToPackages.keyAt(index);
+ boolean overrideable = level <= APPROVAL_LEVEL_SELECTION;
+ List<String> packages = levelToPackages.valueAt(index);
+ int packagesSize = packages.size();
+ for (int packageIndex = 0; packageIndex < packagesSize; packageIndex++) {
+ owners.add(new DomainOwner(packages.get(packageIndex), overrideable));
+ }
+ }
+
+ return owners;
+ }
+
+ @NonNull
+ @Override
public UUID generateNewId() {
// TODO(b/159952358): Domain set ID collisions
return UUID.randomUUID();
@@ -634,7 +783,7 @@
@Override
public void migrateState(@NonNull PackageSetting oldPkgSetting,
@NonNull PackageSetting newPkgSetting) {
- String pkgName = newPkgSetting.name;
+ String pkgName = newPkgSetting.getName();
boolean sendBroadcast;
synchronized (mLock) {
@@ -663,7 +812,8 @@
}
ArrayMap<String, Integer> oldStateMap = oldPkgState.getStateMap();
- ArraySet<String> newAutoVerifyDomains = mCollector.collectAutoVerifyDomains(newPkg);
+ ArraySet<String> newAutoVerifyDomains =
+ mCollector.collectValidAutoVerifyDomains(newPkg);
int newDomainsSize = newAutoVerifyDomains.size();
for (int newDomainsIndex = 0; newDomainsIndex < newDomainsSize; newDomainsIndex++) {
@@ -692,7 +842,7 @@
oldPkgState.getUserSelectionStates();
int oldUserStatesSize = oldUserStates.size();
if (oldUserStatesSize > 0) {
- ArraySet<String> newWebDomains = mCollector.collectAutoVerifyDomains(newPkg);
+ ArraySet<String> newWebDomains = mCollector.collectValidAutoVerifyDomains(newPkg);
for (int oldUserStatesIndex = 0; oldUserStatesIndex < oldUserStatesSize;
oldUserStatesIndex++) {
int userId = oldUserStates.keyAt(oldUserStatesIndex);
@@ -730,7 +880,7 @@
// gains or loses all domains.
UUID domainSetId = newPkgSetting.getDomainSetId();
- String pkgName = newPkgSetting.name;
+ String pkgName = newPkgSetting.getName();
boolean sendBroadcast = true;
@@ -745,7 +895,7 @@
}
AndroidPackage pkg = newPkgSetting.getPkg();
- ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+ ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
boolean hasAutoVerifyDomains = !domains.isEmpty();
boolean isPendingOrRestored = pkgState != null;
if (isPendingOrRestored) {
@@ -1009,7 +1159,7 @@
}
AndroidPackage pkg = pkgSetting.getPkg();
ArraySet<String> declaredDomains = forAutoVerify
- ? mCollector.collectAutoVerifyDomains(pkg)
+ ? mCollector.collectValidAutoVerifyDomains(pkg)
: mCollector.collectAllWebDomains(pkg);
if (domains.retainAll(declaredDomains)) {
@@ -1141,7 +1291,7 @@
}
}
- applyImmutableState(pkgState, mCollector.collectAutoVerifyDomains(pkg));
+ applyImmutableState(pkgState, mCollector.collectValidAutoVerifyDomains(pkg));
}
@Override
@@ -1346,9 +1496,11 @@
@Override
public int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
- @UserIdInt int userId) {
- String packageName = pkgSetting.name;
- if (!DomainVerificationUtils.isDomainVerificationIntent(intent)) {
+ @NonNull List<ResolveInfo> candidates,
+ @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
+ String packageName = pkgSetting.getName();
+ if (!DomainVerificationUtils.isDomainVerificationIntent(intent, candidates,
+ resolveInfoFlags)) {
if (DEBUG_APPROVAL) {
debugApproval(packageName, intent, userId, false, "not valid intent");
}
@@ -1364,7 +1516,7 @@
*/
private int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull String host,
@UserIdInt int userId, @NonNull Object debugObject) {
- String packageName = pkgSetting.name;
+ String packageName = pkgSetting.getName();
final AndroidPackage pkg = pkgSetting.getPkg();
// Should never be null, but if it is, skip this and assume that v2 is enabled
@@ -1409,7 +1561,7 @@
// To allow an instant app to immediately open domains after being installed by the
// user, auto approve them for any declared autoVerify domains.
if (pkgSetting.getInstantApp(userId)
- && mCollector.collectAutoVerifyDomains(pkg).contains(host)) {
+ && mCollector.collectValidAutoVerifyDomains(pkg).contains(host)) {
return APPROVAL_LEVEL_INSTANT_APP;
}
}
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 475d3a8..883bbad 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,12 +22,17 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.os.Binder;
+import com.android.internal.util.CollectionUtils;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import java.util.List;
+import java.util.Set;
+
public final class DomainVerificationUtils {
/**
@@ -40,10 +45,61 @@
throw new NameNotFoundException("Package " + packageName + " unavailable");
}
- public static boolean isDomainVerificationIntent(Intent intent) {
- return intent.isWebIntent()
- && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
- && intent.hasCategory(Intent.CATEGORY_DEFAULT);
+ public static boolean isDomainVerificationIntent(Intent intent,
+ @NonNull List<ResolveInfo> candidates,
+ @PackageManager.ResolveInfoFlags int resolveInfoFlags) {
+ if (!intent.isWebIntent()) {
+ return false;
+ }
+
+ Set<String> categories = intent.getCategories();
+ int categoriesSize = CollectionUtils.size(categories);
+ if (categoriesSize > 2) {
+ // Specifying at least one non-app-link category
+ return false;
+ } else if (categoriesSize == 2) {
+ // Check for explicit app link intent with exactly BROWSABLE && DEFAULT
+ return intent.hasCategory(Intent.CATEGORY_DEFAULT)
+ && intent.hasCategory(Intent.CATEGORY_BROWSABLE);
+ }
+
+ // In cases where at least one browser is resolved and only one non-browser is resolved,
+ // the Intent is coerced into an app links intent, under the assumption the browser can
+ // be skipped if the app is approved at any level for the domain.
+ boolean foundBrowser = false;
+ boolean foundOneApp = false;
+
+ final int candidatesSize = candidates.size();
+ for (int index = 0; index < candidatesSize; index++) {
+ final ResolveInfo info = candidates.get(index);
+ if (info.handleAllWebDataURI) {
+ foundBrowser = true;
+ } else if (foundOneApp) {
+ // Already true, so duplicate app
+ foundOneApp = false;
+ break;
+ } else {
+ foundOneApp = true;
+ }
+ }
+
+ boolean matchDefaultByFlags = (resolveInfoFlags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
+ boolean onlyOneNonBrowser = foundBrowser && foundOneApp;
+
+ // Check if matches (BROWSABLE || none) && DEFAULT
+ if (categoriesSize == 0) {
+ // No categories, run coerce case, matching DEFAULT by flags
+ return onlyOneNonBrowser && matchDefaultByFlags;
+ } else if (intent.hasCategory(Intent.CATEGORY_DEFAULT)) {
+ // Run coerce case, matching by explicit DEFAULT
+ return onlyOneNonBrowser;
+ } else if (intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
+ // Intent matches BROWSABLE, must match DEFAULT by flags
+ return matchDefaultByFlags;
+ } else {
+ // Otherwise not matching any app link categories
+ return false;
+ }
}
static boolean isChangeEnabled(PlatformCompat platformCompat, AndroidPackage pkg,
diff --git a/services/core/java/com/android/server/pm/verify/domain/OWNERS b/services/core/java/com/android/server/pm/verify/domain/OWNERS
new file mode 100644
index 0000000..c669112
--- /dev/null
+++ b/services/core/java/com/android/server/pm/verify/domain/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+
+chiuwinson@google.com
+patb@google.com
+toddke@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
index 2246864..8fbb33a 100644
--- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
+++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
@@ -58,6 +58,11 @@
return this;
}
+ public DomainVerificationUserState removeHost(String host) {
+ mEnabledHosts.remove(host);
+ return this;
+ }
+
public DomainVerificationUserState removeHosts(@NonNull ArraySet<String> newHosts) {
mEnabledHosts.removeAll(newHosts);
return this;
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
index a804065..18042af 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
@@ -16,6 +16,9 @@
package com.android.server.pm.verify.domain.proxy;
+import static android.os.PowerWhitelistManager.REASON_DOMAIN_VERIFICATION_V1;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -238,7 +241,8 @@
final long allowListTimeout = mConnection.getPowerSaveTempWhitelistAppDuration();
mConnection.getDeviceIdleInternal().addPowerSaveTempWhitelistApp(Process.myUid(),
mVerifierComponent.getPackageName(), allowListTimeout,
- UserHandle.USER_SYSTEM, true, "domain verification agent");
+ UserHandle.USER_SYSTEM, true, REASON_DOMAIN_VERIFICATION_V1,
+ "domain verification agent");
int size = verifications.size();
for (int index = 0; index < size; index++) {
@@ -261,7 +265,9 @@
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.setTemporaryAppWhitelistDuration(allowListTimeout);
+ options.setTemporaryAppAllowlist(allowListTimeout,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_DOMAIN_VERIFICATION_V1, "");
mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null, options.toBundle());
}
}
@@ -270,7 +276,7 @@
private String buildHostsString(@NonNull AndroidPackage pkg) {
// The collector itself handles the v1 vs v2 behavior, which is based on targetSdkVersion,
// not the version of the verification agent on device.
- ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+ ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
// v1 doesn't handle wildcard domains, so transform them here to the root
StringBuilder builder = new StringBuilder();
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
index 1ef06036..2ba17d3 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
@@ -16,6 +16,9 @@
package com.android.server.pm.verify.domain.proxy;
+import static android.os.PowerWhitelistManager.REASON_DOMAIN_VERIFICATION_V2;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.BroadcastOptions;
@@ -69,11 +72,14 @@
final long allowListTimeout = mConnection.getPowerSaveTempWhitelistAppDuration();
final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.setTemporaryAppWhitelistDuration(allowListTimeout);
+ options.setTemporaryAppAllowlist(allowListTimeout,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_DOMAIN_VERIFICATION_V2, "");
mConnection.getDeviceIdleInternal().addPowerSaveTempWhitelistApp(Process.myUid(),
mVerifierComponent.getPackageName(), allowListTimeout,
- UserHandle.USER_SYSTEM, true, "domain verification agent");
+ UserHandle.USER_SYSTEM, true, REASON_DOMAIN_VERIFICATION_V2,
+ "domain verification agent");
Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION)
.setComponent(mVerifierComponent)
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
new file mode 100644
index 0000000..c965390
--- /dev/null
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -0,0 +1,151 @@
+/*
+ * 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.policy;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
+import android.location.LocationManagerInternal;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.function.HeptFunction;
+import com.android.internal.util.function.QuadFunction;
+import com.android.server.LocalServices;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class defines policy for special behaviors around app ops.
+ */
+public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegate {
+ @NonNull
+ private final Object mLock = new Object();
+
+ /**
+ * The locking policy around the location tags is a bit special. Since we want to
+ * avoid grabbing the lock on every op note we are taking the approach where the
+ * read and write are being done via a thread-safe data structure such that the
+ * lookup/insert are single thread-safe calls. When we update the cached state we
+ * use a lock to ensure the update's lookup and store calls are done atomically,
+ * so multiple writers would not interleave. The tradeoff is we make is that the
+ * concurrent data structure would use boxing/unboxing of integers but this is
+ * preferred to locking.
+ */
+ @GuardedBy("mLock - writes only - see above")
+ @NonNull
+ private final ConcurrentHashMap<Integer, ArrayMap<String, ArraySet<String>>> mLocationTags =
+ new ConcurrentHashMap();
+
+ public AppOpsPolicy() {
+ final LocationManagerInternal locationManagerInternal = LocalServices.getService(
+ LocationManagerInternal.class);
+ locationManagerInternal.setOnProviderLocationTagsChangeListener((providerTagInfo) -> {
+ synchronized (mLock) {
+ final int uid = providerTagInfo.getUid();
+ // We make a copy of the per UID state to limit our mutation to one
+ // operation in the underlying concurrent data structure.
+ ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
+ if (uidTags != null) {
+ uidTags = new ArrayMap<>(uidTags);
+ }
+
+ final String packageName = providerTagInfo.getPackageName();
+ ArraySet<String> packageTags = (uidTags != null) ? uidTags.get(packageName) : null;
+ if (packageTags != null) {
+ packageTags = new ArraySet<>(packageTags);
+ }
+
+ final Set<String> providerTags = providerTagInfo.getTags();
+ if (providerTags != null && !providerTags.isEmpty()) {
+ if (packageTags != null) {
+ packageTags.clear();
+ packageTags.addAll(providerTags);
+ } else {
+ packageTags = new ArraySet<>(providerTags);
+ }
+ if (uidTags == null) {
+ uidTags = new ArrayMap<>();
+ }
+ uidTags.put(packageName, packageTags);
+ mLocationTags.put(uid, uidTags);
+ } else if (uidTags != null) {
+ uidTags.remove(packageName);
+ if (!uidTags.isEmpty()) {
+ mLocationTags.put(uid, uidTags);
+ } else {
+ mLocationTags.remove(uid);
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public int checkOperation(int code, int uid, String packageName, boolean raw,
+ QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
+ return superImpl.apply(code, uid, packageName, raw);
+ }
+
+ @Override
+ public int checkAudioOperation(int code, int usage, int uid, String packageName,
+ QuadFunction<Integer, Integer, Integer, String, Integer> superImpl) {
+ return superImpl.apply(code, usage, uid, packageName);
+ }
+
+ @Override
+ public int noteOperation(int code, int uid, @Nullable String packageName,
+ @Nullable String featureId, boolean shouldCollectAsyncNotedOp, @Nullable String message,
+ boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer, String, String,
+ Boolean, String, Boolean, Integer> superImpl) {
+ if (isHandledOp(code)) {
+ // Only a single lookup from the underlying concurrent data structure
+ final ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
+ if (uidTags != null) {
+ final ArraySet<String> packageTags = uidTags.get(packageName);
+ if (packageTags != null && packageTags.contains(featureId)) {
+ return superImpl.apply(resolveLocationOp(code), uid, packageName, featureId,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ }
+ }
+ }
+ return superImpl.apply(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+ message, shouldCollectMessage);
+ }
+
+ private static boolean isHandledOp(int code) {
+ switch (code) {
+ case AppOpsManager.OP_FINE_LOCATION:
+ case AppOpsManager.OP_COARSE_LOCATION:
+ return true;
+ }
+ return false;
+ }
+
+ private static int resolveLocationOp(int code) {
+ switch (code) {
+ case AppOpsManager.OP_FINE_LOCATION:
+ return AppOpsManager.OP_FINE_LOCATION_SOURCE;
+ case AppOpsManager.OP_COARSE_LOCATION:
+ return AppOpsManager.OP_COARSE_LOCATION_SOURCE;
+ }
+ return code;
+ }
+}
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index 82fc22c..0e12584 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -74,7 +74,7 @@
mHandler = handler;
DeviceStateManager deviceStateManager = context.getSystemService(DeviceStateManager.class);
- deviceStateManager.addDeviceStateListener(new HandlerExecutor(handler),
+ deviceStateManager.registerCallback(new HandlerExecutor(handler),
new DeviceStateListener(context));
}
@@ -208,7 +208,7 @@
* matches the value in the {@link com.android.internal.R.integer.config_foldedDeviceState}
* resource.
*/
- private class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+ private class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
private final int[] mFoldedDeviceStates;
DeviceStateListener(Context context) {
@@ -217,7 +217,7 @@
}
@Override
- public void onDeviceStateChanged(int deviceState) {
+ public void onStateChanged(int deviceState) {
boolean folded = false;
for (int i = 0; i < mFoldedDeviceStates.length; i++) {
if (deviceState == mFoldedDeviceStates[i]) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4ccd57d..c50efc7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -520,8 +520,6 @@
boolean mConsumeSearchKeyUp;
boolean mPendingMetaAction;
boolean mPendingCapsLockToggle;
- int mMetaState;
- int mInitialMetaState;
// support for activating the lock screen while the screen is on
private HashSet<Integer> mAllowLockscreenWhenOnDisplays = new HashSet<>();
@@ -2547,6 +2545,7 @@
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int displayId = event.getDisplayId();
+ final long key_consumed = -1;
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
@@ -2554,7 +2553,7 @@
}
if (mKeyCombinationManager.isKeyConsumed(event)) {
- return -1;
+ return key_consumed;
}
if ((flags & KeyEvent.FLAG_FALLBACK) == 0) {
@@ -2575,205 +2574,250 @@
mPendingCapsLockToggle = false;
}
- // First we always handle the home key here, so applications
- // can never break it, although if keyguard is on, we do let
- // it handle it, because that gives us the correct 5 second
- // timeout.
- if (keyCode == KEYCODE_HOME) {
- DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
- if (handler == null) {
- handler = new DisplayHomeButtonHandler(displayId);
- mDisplayHomeButtonHandlers.put(displayId, handler);
- }
- return handler.handleHomeButton(focusedToken, event);
- } else if (keyCode == KeyEvent.KEYCODE_MENU) {
- // Hijack modified menu keys for debugging features
- final int chordBug = KeyEvent.META_SHIFT_ON;
+ switch(keyCode) {
+ case KeyEvent.KEYCODE_HOME:
+ // First we always handle the home key here, so applications
+ // can never break it, although if keyguard is on, we do let
+ // it handle it, because that gives us the correct 5 second
+ // timeout.
+ DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
+ if (handler == null) {
+ handler = new DisplayHomeButtonHandler(displayId);
+ mDisplayHomeButtonHandlers.put(displayId, handler);
+ }
+ return handler.handleHomeButton(focusedToken, event);
+ case KeyEvent.KEYCODE_MENU:
+ // Hijack modified menu keys for debugging features
+ final int chordBug = KeyEvent.META_SHIFT_ON;
- if (down && repeatCount == 0) {
- if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
- Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
- null, null, null, 0, null, null);
- return -1;
- }
- }
- } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
- if (down) {
- if (repeatCount == 0) {
- mSearchKeyShortcutPending = true;
- mConsumeSearchKeyUp = false;
- }
- } else {
- mSearchKeyShortcutPending = false;
- if (mConsumeSearchKeyUp) {
- mConsumeSearchKeyUp = false;
- return -1;
- }
- }
- return 0;
- } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
- if (!keyguardOn) {
if (down && repeatCount == 0) {
- preloadRecentApps();
- } else if (!down) {
- toggleRecentApps();
- }
- }
- return -1;
- } else if (keyCode == KeyEvent.KEYCODE_N && event.isMetaPressed()) {
- if (down) {
- IStatusBarService service = getStatusBarService();
- if (service != null) {
- try {
- service.expandNotificationsPanel();
- } catch (RemoteException e) {
- // do nothing.
+ if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
+ Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
+ null, null, null, 0, null, null);
+ return key_consumed;
}
}
- }
- } else if (keyCode == KeyEvent.KEYCODE_S && event.isMetaPressed()
- && event.isCtrlPressed()) {
- if (down && repeatCount == 0) {
- int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
- : TAKE_SCREENSHOT_FULLSCREEN;
- mScreenshotRunnable.setScreenshotType(type);
- mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
- mHandler.post(mScreenshotRunnable);
- return -1;
- }
- } else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
- if (down && repeatCount == 0 && !isKeyguardLocked()) {
- toggleKeyboardShortcutsMenu(event.getDeviceId());
- }
- } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
- Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
- return -1;
- } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) {
- Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in interceptKeyBeforeQueueing");
- return -1;
- } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
- if (down && repeatCount == 0) {
- mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
- mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
- mHandler.post(mScreenshotRunnable);
- }
- return -1;
- } else if (keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP
- || keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN) {
- if (down) {
- int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
+ break;
+ case KeyEvent.KEYCODE_SEARCH:
+ if (down) {
+ if (repeatCount == 0) {
+ mSearchKeyShortcutPending = true;
+ mConsumeSearchKeyUp = false;
+ }
+ } else {
+ mSearchKeyShortcutPending = false;
+ if (mConsumeSearchKeyUp) {
+ mConsumeSearchKeyUp = false;
+ return key_consumed;
+ }
+ }
+ return 0;
+ case KeyEvent.KEYCODE_APP_SWITCH:
+ if (!keyguardOn) {
+ if (down && repeatCount == 0) {
+ preloadRecentApps();
+ } else if (!down) {
+ toggleRecentApps();
+ }
+ }
+ return key_consumed;
+ case KeyEvent.KEYCODE_N:
+ if (down && event.isMetaPressed()) {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.expandNotificationsPanel();
+ } catch (RemoteException e) {
+ // do nothing.
+ }
+ return key_consumed;
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_S:
+ if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
+ int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
+ : TAKE_SCREENSHOT_FULLSCREEN;
+ mScreenshotRunnable.setScreenshotType(type);
+ mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
+ mHandler.post(mScreenshotRunnable);
+ return key_consumed;
+ }
+ break;
+ case KeyEvent.KEYCODE_SLASH:
+ if (down && repeatCount == 0 && event.isMetaPressed() && !keyguardOn) {
+ toggleKeyboardShortcutsMenu(event.getDeviceId());
+ return key_consumed;
+ }
+ break;
+ case KeyEvent.KEYCODE_ASSIST:
+ Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
+ return key_consumed;
+ case KeyEvent.KEYCODE_VOICE_ASSIST:
+ Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in"
+ + " interceptKeyBeforeQueueing");
+ return key_consumed;
+ case KeyEvent.KEYCODE_SYSRQ:
+ if (down && repeatCount == 0) {
+ mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
+ mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
+ mHandler.post(mScreenshotRunnable);
+ }
+ return key_consumed;
+ case KeyEvent.KEYCODE_BRIGHTNESS_UP:
+ case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
+ if (down) {
+ int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
- // Disable autobrightness if it's on
- int auto = Settings.System.getIntForUser(
- mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_MODE,
- Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
- UserHandle.USER_CURRENT_OR_SELF);
- if (auto != 0) {
- Settings.System.putIntForUser(mContext.getContentResolver(),
+ // Disable autobrightness if it's on
+ int auto = Settings.System.getIntForUser(
+ mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
UserHandle.USER_CURRENT_OR_SELF);
+ if (auto != 0) {
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+ UserHandle.USER_CURRENT_OR_SELF);
+ }
+ float minFloat = mPowerManager.getBrightnessConstraint(
+ PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
+ float maxFloat = mPowerManager.getBrightnessConstraint(
+ PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
+ float stepFloat = (maxFloat - minFloat) / BRIGHTNESS_STEPS * direction;
+ float brightnessFloat = Settings.System.getFloatForUser(
+ mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_FLOAT,
+ mContext.getDisplay().getBrightnessDefault(),
+ UserHandle.USER_CURRENT_OR_SELF);
+ brightnessFloat += stepFloat;
+ // Make sure we don't go beyond the limits.
+ brightnessFloat = Math.min(maxFloat, brightnessFloat);
+ brightnessFloat = Math.max(minFloat, brightnessFloat);
+
+ Settings.System.putFloatForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_FLOAT, brightnessFloat,
+ UserHandle.USER_CURRENT_OR_SELF);
+ startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
+ UserHandle.CURRENT_OR_SELF);
}
- float minFloat = mPowerManager.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
- float maxFloat = mPowerManager.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
- float stepFloat = (maxFloat - minFloat) / BRIGHTNESS_STEPS * direction;
- float brightnessFloat = Settings.System.getFloatForUser(
- mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_FLOAT,
- mContext.getDisplay().getBrightnessDefault(),
- UserHandle.USER_CURRENT_OR_SELF);
- brightnessFloat += stepFloat;
- // Make sure we don't go beyond the limits.
- brightnessFloat = Math.min(maxFloat, brightnessFloat);
- brightnessFloat = Math.max(minFloat, brightnessFloat);
-
- Settings.System.putFloatForUser(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_FLOAT, brightnessFloat,
- UserHandle.USER_CURRENT_OR_SELF);
- startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
- UserHandle.CURRENT_OR_SELF);
- }
- return -1;
- } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP
- || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
- || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
- if (mUseTvRouting || mHandleVolumeKeysInWM) {
- // On TVs or when the configuration is enabled, volume keys never
- // go to the foreground app.
- dispatchDirectAudioEvent(event);
- return -1;
- }
-
- // If the device is in VR mode and keys are "internal" (e.g. on the side of the
- // device), then drop the volume keys and don't forward it to the application/dispatch
- // the audio event.
- if (mDefaultDisplayPolicy.isPersistentVrModeEnabled()) {
- final InputDevice d = event.getDevice();
- if (d != null && !d.isExternal()) {
- return -1;
+ return key_consumed;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ if (mUseTvRouting || mHandleVolumeKeysInWM) {
+ // On TVs or when the configuration is enabled, volume keys never
+ // go to the foreground app.
+ dispatchDirectAudioEvent(event);
+ return key_consumed;
}
- }
- } else if (keyCode == KeyEvent.KEYCODE_TAB && event.isMetaPressed()) {
- // Pass through keyboard navigation keys.
- return 0;
- } else if (keyCode == KeyEvent.KEYCODE_ALL_APPS) {
- if (!down) {
- mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
- Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS);
- msg.setAsynchronous(true);
- msg.sendToTarget();
- }
- return -1;
- } else if (keyCode == KeyEvent.KEYCODE_NOTIFICATION) {
- if (!down) {
- toggleNotificationPanel();
- }
- return -1;
- }
- // Toggle Caps Lock on META-ALT.
- boolean actionTriggered = false;
- if (KeyEvent.isModifierKey(keyCode)) {
- if (!mPendingCapsLockToggle) {
- // Start tracking meta state for combo.
- mInitialMetaState = mMetaState;
- mPendingCapsLockToggle = true;
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- int altOnMask = mMetaState & KeyEvent.META_ALT_MASK;
- int metaOnMask = mMetaState & KeyEvent.META_META_MASK;
-
- // Check for Caps Lock toggle
- if ((metaOnMask != 0) && (altOnMask != 0)) {
- // Check if nothing else is pressed
- if (mInitialMetaState == (mMetaState ^ (altOnMask | metaOnMask))) {
- // Handle Caps Lock Toggle
- mInputManagerInternal.toggleCapsLock(event.getDeviceId());
- actionTriggered = true;
+ // If the device is in VR mode and keys are "internal" (e.g. on the side of the
+ // device), then drop the volume keys and don't forward it to the
+ // application/dispatch the audio event.
+ if (mDefaultDisplayPolicy.isPersistentVrModeEnabled()) {
+ final InputDevice d = event.getDevice();
+ if (d != null && !d.isExternal()) {
+ return key_consumed;
}
}
+ break;
+ case KeyEvent.KEYCODE_TAB:
+ if (event.isMetaPressed()) {
+ // Pass through keyboard navigation keys.
+ return 0;
+ }
+ // Display task switcher for ALT-TAB.
+ if (down && repeatCount == 0) {
+ if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
+ final int shiftlessModifiers =
+ event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+ if (KeyEvent.metaStateHasModifiers(
+ shiftlessModifiers, KeyEvent.META_ALT_ON)) {
+ mRecentAppsHeldModifiers = shiftlessModifiers;
+ showRecentApps(true);
+ return key_consumed;
+ }
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_ALL_APPS:
+ if (!down) {
+ mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
+ Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+ return key_consumed;
+ case KeyEvent.KEYCODE_NOTIFICATION:
+ if (!down) {
+ toggleNotificationPanel();
+ }
+ return key_consumed;
- // Always stop tracking when key goes up.
- mPendingCapsLockToggle = false;
- }
- }
- // Store current meta state to be able to evaluate it later.
- mMetaState = metaState;
+ case KeyEvent.KEYCODE_SPACE:
+ // Handle keyboard layout switching.
+ if ((metaState & (KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK)) == 0) {
+ return 0;
+ }
+ // Share the same behavior with KEYCODE_LANGUAGE_SWITCH.
+ case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
+ if (down && repeatCount == 0) {
+ int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+ mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+ return key_consumed;
+ }
+ break;
+ case KeyEvent.KEYCODE_META_LEFT:
+ case KeyEvent.KEYCODE_META_RIGHT:
+ if (down) {
+ if (event.isAltPressed()) {
+ mPendingCapsLockToggle = true;
+ mPendingMetaAction = false;
+ } else {
+ mPendingCapsLockToggle = false;
+ mPendingMetaAction = true;
+ }
+ } else {
+ // Toggle Caps Lock on META-ALT.
+ if (mPendingCapsLockToggle) {
+ mInputManagerInternal.toggleCapsLock(event.getDeviceId());
+ mPendingCapsLockToggle = false;
+ } else if (mPendingMetaAction) {
+ launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
+ event.getDeviceId(),
+ event.getEventTime());
+ mPendingMetaAction = false;
+ }
+ }
+ return key_consumed;
+ case KeyEvent.KEYCODE_ALT_LEFT:
+ case KeyEvent.KEYCODE_ALT_RIGHT:
+ if (down) {
+ if (event.isMetaPressed()) {
+ mPendingCapsLockToggle = true;
+ mPendingMetaAction = false;
+ } else {
+ mPendingCapsLockToggle = false;
+ }
+ } else {
+ // hide recent if triggered by ALT-TAB.
+ if (mRecentAppsHeldModifiers != 0
+ && (metaState & mRecentAppsHeldModifiers) == 0) {
+ mRecentAppsHeldModifiers = 0;
+ hideRecentApps(true, false);
+ return key_consumed;
+ }
- if (actionTriggered) {
- return -1;
- }
-
- if (KeyEvent.isMetaKey(keyCode)) {
- if (down) {
- mPendingMetaAction = true;
- } else if (mPendingMetaAction) {
- launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD, event.getDeviceId(),
- event.getEventTime());
- }
- return -1;
+ // Toggle Caps Lock on META-ALT.
+ if (mPendingCapsLockToggle) {
+ mInputManagerInternal.toggleCapsLock(event.getDeviceId());
+ mPendingCapsLockToggle = false;
+ return key_consumed;
+ }
+ }
+ break;
}
// Shortcuts are invoked through Search+key, so intercept those here
@@ -2803,7 +2847,7 @@
+ "SEARCH+" + KeyEvent.keyCodeToString(keyCode));
}
}
- return -1;
+ return key_consumed;
}
}
@@ -2825,7 +2869,7 @@
+ "the activity to which it is registered was not found: "
+ "META+" + KeyEvent.keyCodeToString(keyCode), ex);
}
- return -1;
+ return key_consumed;
}
}
}
@@ -2844,39 +2888,13 @@
+ "the activity to which it is registered was not found: "
+ "keyCode=" + keyCode + ", category=" + category, ex);
}
- return -1;
+ return key_consumed;
}
}
- // Display task switcher for ALT-TAB.
- if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
- if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
- final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
- if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) {
- mRecentAppsHeldModifiers = shiftlessModifiers;
- showRecentApps(true);
- return -1;
- }
- }
- } else if (!down && mRecentAppsHeldModifiers != 0
- && (metaState & mRecentAppsHeldModifiers) == 0) {
- mRecentAppsHeldModifiers = 0;
- hideRecentApps(true, false);
- }
-
- // Handle keyboard language switching.
- final boolean isCtrlOrMetaSpace = keyCode == KeyEvent.KEYCODE_SPACE
- && (metaState & (KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK)) != 0;
- if (down && repeatCount == 0
- && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH || isCtrlOrMetaSpace)) {
- int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
- mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
- return -1;
- }
-
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
- return -1;
+ return key_consumed;
}
if (down) {
@@ -2906,13 +2924,13 @@
} catch (RemoteException e) {
mShortcutKeyServices.delete(shortcutCode);
}
- return -1;
+ return key_consumed;
}
}
// Reserve all the META modifier combos for system behavior
if ((metaState & KeyEvent.META_META_ON) != 0) {
- return -1;
+ return key_consumed;
}
// Let the application handle the key.
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index c4f29ea..ef0079e 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -16,6 +16,8 @@
package com.android.server.powerstats;
+import static java.lang.System.currentTimeMillis;
+
import android.content.Context;
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyConsumer;
@@ -26,11 +28,14 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
+
import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
import com.android.server.powerstats.ProtoStreamUtils.ChannelUtils;
import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerResultUtils;
@@ -61,6 +66,8 @@
protected static final int MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY = 1;
protected static final int MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY = 2;
+ // TODO(b/181240441): Add a listener to update the Wall clock baseline when changed
+ private final long mStartWallTime;
private final PowerStatsDataStorage mPowerStatsMeterStorage;
private final PowerStatsDataStorage mPowerStatsModelStorage;
private final PowerStatsDataStorage mPowerStatsResidencyStorage;
@@ -79,6 +86,8 @@
// Log power meter data.
EnergyMeasurement[] energyMeasurements =
mPowerStatsHALWrapper.readEnergyMeter(new int[0]);
+ EnergyMeasurementUtils.adjustTimeSinceBootToEpoch(energyMeasurements,
+ mStartWallTime);
mPowerStatsMeterStorage.write(
EnergyMeasurementUtils.getProtoBytes(energyMeasurements));
if (DEBUG) EnergyMeasurementUtils.print(energyMeasurements);
@@ -86,6 +95,8 @@
// Log power model data without attribution data.
EnergyConsumerResult[] ecrNoAttribution =
mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
+ EnergyConsumerResultUtils.adjustTimeSinceBootToEpoch(ecrNoAttribution,
+ mStartWallTime);
mPowerStatsModelStorage.write(
EnergyConsumerResultUtils.getProtoBytes(ecrNoAttribution, false));
if (DEBUG) EnergyConsumerResultUtils.print(ecrNoAttribution);
@@ -97,6 +108,8 @@
// Log power model data with attribution data.
EnergyConsumerResult[] ecrAttribution =
mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
+ EnergyConsumerResultUtils.adjustTimeSinceBootToEpoch(ecrAttribution,
+ mStartWallTime);
mPowerStatsModelStorage.write(
EnergyConsumerResultUtils.getProtoBytes(ecrAttribution, true));
if (DEBUG) EnergyConsumerResultUtils.print(ecrAttribution);
@@ -108,6 +121,8 @@
// Log state residency data.
StateResidencyResult[] stateResidencyResults =
mPowerStatsHALWrapper.getStateResidency(new int[0]);
+ StateResidencyResultUtils.adjustTimeSinceBootToEpoch(stateResidencyResults,
+ mStartWallTime);
mPowerStatsResidencyStorage.write(
StateResidencyResultUtils.getProtoBytes(stateResidencyResults));
if (DEBUG) StateResidencyResultUtils.print(stateResidencyResults);
@@ -293,12 +308,19 @@
return mDeleteResidencyDataOnBoot;
}
+ @VisibleForTesting
+ public long getStartWallTime() {
+ return mStartWallTime;
+ }
+
public PowerStatsLogger(Context context, File dataStoragePath,
String meterFilename, String meterCacheFilename,
String modelFilename, String modelCacheFilename,
String residencyFilename, String residencyCacheFilename,
IPowerStatsHALWrapper powerStatsHALWrapper) {
super(Looper.getMainLooper());
+ mStartWallTime = currentTimeMillis() - SystemClock.elapsedRealtime();
+ if (DEBUG) Slog.d(TAG, "mStartWallTime: " + mStartWallTime);
mPowerStatsHALWrapper = powerStatsHALWrapper;
mDataStoragePath = dataStoragePath;
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 11b22a5..746a098 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -109,6 +109,18 @@
}
static class StateResidencyResultUtils {
+ public static void adjustTimeSinceBootToEpoch(StateResidencyResult[] stateResidencyResult,
+ long startWallTime) {
+ for (int i = 0; i < stateResidencyResult.length; i++) {
+ final int stateLength = stateResidencyResult[i].stateResidencyData.length;
+ for (int j = 0; j < stateLength; j++) {
+ final StateResidency stateResidencyData =
+ stateResidencyResult[i].stateResidencyData[j];
+ stateResidencyData.lastEntryTimestampMs += startWallTime;
+ }
+ }
+ }
+
public static byte[] getProtoBytes(StateResidencyResult[] stateResidencyResult) {
ProtoOutputStream pos = new ProtoOutputStream();
packProtoMessage(stateResidencyResult, pos);
@@ -306,6 +318,13 @@
}
static class EnergyMeasurementUtils {
+ public static void adjustTimeSinceBootToEpoch(EnergyMeasurement[] energyMeasurement,
+ long startWallTime) {
+ for (int i = 0; i < energyMeasurement.length; i++) {
+ energyMeasurement[i].timestampMs += startWallTime;
+ }
+ }
+
public static byte[] getProtoBytes(EnergyMeasurement[] energyMeasurement) {
ProtoOutputStream pos = new ProtoOutputStream();
packProtoMessage(energyMeasurement, pos);
@@ -518,6 +537,13 @@
}
static class EnergyConsumerResultUtils {
+ public static void adjustTimeSinceBootToEpoch(EnergyConsumerResult[] energyConsumerResult,
+ long startWallTime) {
+ for (int i = 0; i < energyConsumerResult.length; i++) {
+ energyConsumerResult[i].timestampMs += startWallTime;
+ }
+ }
+
public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult,
boolean includeAttribution) {
ProtoOutputStream pos = new ProtoOutputStream();
diff --git a/services/core/java/com/android/server/security/KeyChainSystemService.java b/services/core/java/com/android/server/security/KeyChainSystemService.java
index 3c06d0e..edd4a3d 100644
--- a/services/core/java/com/android/server/security/KeyChainSystemService.java
+++ b/services/core/java/com/android/server/security/KeyChainSystemService.java
@@ -16,6 +16,8 @@
package com.android.server.security;
+import static android.os.PowerWhitelistManager.REASON_KEY_CHAIN;
+
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -102,7 +104,8 @@
final DeviceIdleInternal idleController =
LocalServices.getService(DeviceIdleInternal.class);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
- KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false, "keychain");
+ KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false,
+ REASON_KEY_CHAIN, "keychain");
getContext().startServiceAsUser(intent, user);
}
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 0087c0c..dedb3ac 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -32,6 +32,7 @@
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.provider.MediaStore;
@@ -162,22 +163,17 @@
*
* @return ANR dialog delay in milliseconds
*/
- public long getAnrDelayMillis(String packageName, int uid)
+ public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
throws ExternalStorageServiceException {
+ final int userId = UserHandle.getUserId(uid);
+ final StorageUserConnection connection;
synchronized (mLock) {
- int size = mConnections.size();
- for (int i = 0; i < size; i++) {
- int key = mConnections.keyAt(i);
- StorageUserConnection connection = mConnections.get(key);
- if (connection != null) {
- long delay = connection.getAnrDelayMillis(packageName, uid);
- if (delay > 0) {
- return delay;
- }
- }
- }
+ connection = mConnections.get(userId);
}
- return 0;
+
+ if (connection != null) {
+ connection.notifyAnrDelayStarted(packageName, uid, tid, reason);
+ }
}
/**
@@ -371,6 +367,60 @@
return mExternalStorageServiceComponent;
}
+ /**
+ * Notify the controller that an app with {@code uid} and {@code tid} is blocked on an IO
+ * request on {@code volumeUuid} for {@code reason}.
+ *
+ * This blocked state can be queried with {@link #isAppIoBlocked}
+ *
+ * @hide
+ */
+ public void notifyAppIoBlocked(String volumeUuid, int uid, int tid,
+ @StorageManager.AppIoBlockedReason int reason) {
+ final int userId = UserHandle.getUserId(uid);
+ final StorageUserConnection connection;
+ synchronized (mLock) {
+ connection = mConnections.get(userId);
+ }
+
+ if (connection != null) {
+ connection.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
+ }
+ }
+
+ /**
+ * Notify the controller that an app with {@code uid} and {@code tid} has resmed a previously
+ * blocked IO request on {@code volumeUuid} for {@code reason}.
+ *
+ * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
+ */
+ public void notifyAppIoResumed(String volumeUuid, int uid, int tid,
+ @StorageManager.AppIoBlockedReason int reason) {
+ final int userId = UserHandle.getUserId(uid);
+ final StorageUserConnection connection;
+ synchronized (mLock) {
+ connection = mConnections.get(userId);
+ }
+
+ if (connection != null) {
+ connection.notifyAppIoResumed(volumeUuid, uid, tid, reason);
+ }
+ }
+
+ /** Returns {@code true} if {@code uid} is blocked on IO, {@code false} otherwise */
+ public boolean isAppIoBlocked(int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ final StorageUserConnection connection;
+ synchronized (mLock) {
+ connection = mConnections.get(userId);
+ }
+
+ if (connection != null) {
+ return connection.isAppIoBlocked(uid);
+ }
+ return false;
+ }
+
private void killExternalStorageService(int userId) {
IActivityManager am = ActivityManager.getService();
try {
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 709d558..d2b05c0 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -16,7 +16,6 @@
package com.android.server.storage;
-import static android.service.storage.ExternalStorageService.EXTRA_ANR_TIMEOUT_MS;
import static android.service.storage.ExternalStorageService.EXTRA_ERROR;
import static android.service.storage.ExternalStorageService.FLAG_SESSION_ATTRIBUTE_INDEXABLE;
import static android.service.storage.ExternalStorageService.FLAG_SESSION_TYPE_FUSE;
@@ -38,10 +37,12 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageVolume;
import android.service.storage.ExternalStorageService;
import android.service.storage.IExternalStorageService;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -73,6 +74,7 @@
private final StorageSessionController mSessionController;
private final ActiveConnection mActiveConnection = new ActiveConnection();
@GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
+ @GuardedBy("mLock") private final Set<Integer> mUidsBlockedOnIo = new ArraySet<>();
private final HandlerThread mHandlerThread;
public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
@@ -148,17 +150,13 @@
*
* @return ANR dialog delay in milliseconds
*/
- public long getAnrDelayMillis(String packageName, int uid)
+ public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
throws ExternalStorageServiceException {
synchronized (mSessionsLock) {
for (String sessionId : mSessions.keySet()) {
- long delay = mActiveConnection.getAnrDelayMillis(packageName, uid);
- if (delay > 0) {
- return delay;
- }
+ mActiveConnection.notifyAnrDelayStarted(packageName, uid, tid, reason);
}
}
- return 0;
}
/**
@@ -170,6 +168,7 @@
**/
public Session removeSession(String sessionId) {
synchronized (mSessionsLock) {
+ mUidsBlockedOnIo.clear();
return mSessions.remove(sessionId);
}
}
@@ -232,6 +231,41 @@
}
}
+ /**
+ * Notify the controller that an app with {@code uid} and {@code tid} is blocked on an IO
+ * request on {@code volumeUuid} for {@code reason}.
+ *
+ * This blocked state can be queried with {@link #isAppIoBlocked}
+ *
+ * @hide
+ */
+ public void notifyAppIoBlocked(String volumeUuid, int uid, int tid,
+ @StorageManager.AppIoBlockedReason int reason) {
+ synchronized (mSessionsLock) {
+ mUidsBlockedOnIo.add(uid);
+ }
+ }
+
+ /**
+ * Notify the connection that an app with {@code uid} and {@code tid} has resmed a previously
+ * blocked IO request on {@code volumeUuid} for {@code reason}.
+ *
+ * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
+ */
+ public void notifyAppIoResumed(String volumeUuid, int uid, int tid,
+ @StorageManager.AppIoBlockedReason int reason) {
+ synchronized (mSessionsLock) {
+ mUidsBlockedOnIo.remove(uid);
+ }
+ }
+
+ /** Returns {@code true} if {@code uid} is blocked on IO, {@code false} otherwise */
+ public boolean isAppIoBlocked(int uid) {
+ synchronized (mSessionsLock) {
+ return mUidsBlockedOnIo.contains(uid);
+ }
+ }
+
@FunctionalInterface
interface AsyncStorageServiceCall {
void run(@NonNull IExternalStorageService service, RemoteCallback callback) throws
@@ -253,9 +287,6 @@
@GuardedBy("mLock")
private final ArrayList<CompletableFuture<Void>> mOutstandingOps = new ArrayList<>();
- @GuardedBy("mLock")
- private final ArrayList<CompletableFuture<Long>> mOutstandingTimeoutOps = new ArrayList<>();
-
@Override
public void close() {
ServiceConnection oldConnection = null;
@@ -272,9 +303,6 @@
for (CompletableFuture<Void> op : mOutstandingOps) {
op.cancel(true);
}
- for (CompletableFuture<Long> op : mOutstandingTimeoutOps) {
- op.cancel(true);
- }
mOutstandingOps.clear();
}
@@ -297,15 +325,6 @@
DEFAULT_REMOTE_TIMEOUT_SECONDS);
}
- private long waitForAsyncLong(AsyncStorageServiceCall asyncCall) throws Exception {
- CompletableFuture<Long> opFuture = new CompletableFuture<>();
- RemoteCallback callback =
- new RemoteCallback(result -> setTimeoutResult(result, opFuture));
-
- return waitForAsync(asyncCall, callback, opFuture, mOutstandingTimeoutOps,
- 1 /* timeoutSeconds */);
- }
-
private <T> T waitForAsync(AsyncStorageServiceCall asyncCall, RemoteCallback callback,
CompletableFuture<T> opFuture, ArrayList<CompletableFuture<T>> outstandingOps,
long timeoutSeconds) throws Exception {
@@ -380,27 +399,17 @@
}
}
- public long getAnrDelayMillis(String packgeName, int uid)
+ public void notifyAnrDelayStarted(String packgeName, int uid, int tid, int reason)
throws ExternalStorageServiceException {
try {
- return waitForAsyncLong((service, callback) ->
- service.getAnrDelayMillis(packgeName, uid, callback));
+ waitForAsyncVoid((service, callback) ->
+ service.notifyAnrDelayStarted(packgeName, uid, tid, reason, callback));
} catch (Exception e) {
- throw new ExternalStorageServiceException("Failed to notify app not responding: "
+ throw new ExternalStorageServiceException("Failed to notify ANR delay started: "
+ packgeName, e);
}
}
- private void setTimeoutResult(Bundle result, CompletableFuture<Long> future) {
- ParcelableException ex = result.getParcelable(EXTRA_ERROR);
- if (ex != null) {
- future.completeExceptionally(ex);
- } else {
- long timeoutMs = result.getLong(EXTRA_ANR_TIMEOUT_MS);
- future.complete(timeoutMs);
- }
- }
-
private void setResult(Bundle result, CompletableFuture<Void> future) {
ParcelableException ex = result.getParcelable(EXTRA_ERROR);
if (ex != null) {
diff --git a/services/core/java/com/android/server/telecom/InternalServiceRepository.java b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
index 76ea5c7..bd1746d 100644
--- a/services/core/java/com/android/server/telecom/InternalServiceRepository.java
+++ b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
@@ -16,6 +16,8 @@
package com.android.server.telecom;
+import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
+
import android.content.Context;
import android.os.Binder;
import android.os.Process;
@@ -38,7 +40,7 @@
public void exemptAppTemporarilyForEvent(String packageName, long duration, int userHandle,
String reason) {
mDeviceIdleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
- duration, userHandle, true /*sync*/, reason);
+ duration, userHandle, true /*sync*/, REASON_UNKNOWN, reason);
}
};
diff --git a/services/core/java/com/android/server/timedetector/DeviceConfig.java b/services/core/java/com/android/server/timedetector/DeviceConfig.java
deleted file mode 100644
index 7b9ad0f..0000000
--- a/services/core/java/com/android/server/timedetector/DeviceConfig.java
+++ /dev/null
@@ -1,126 +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 com.android.server.timedetector;
-
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
-
-import java.time.Duration;
-import java.util.concurrent.Executor;
-
-/**
- * A helper class for reading / monitoring the {@link
- * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace for server-configured flags.
- */
-public final class DeviceConfig {
-
- /**
- * An annotation used to indicate when a {@link
- * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} key is required.
- *
- * <p>Note that the com.android.geotz module deployment of the Offline LocationTimeZoneProvider
- * also shares the {@link android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME}, and uses the
- * prefix "geotz_" on all of its key strings.
- */
- @StringDef(prefix = "KEY_", value = {
- KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED,
- KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT,
- KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
- KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
- KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
- })
- @interface DeviceConfigKey {}
-
- /**
- * The key to force location time zone detection on for a device. Only intended for use during
- * release testing with droidfooders. The user can still disable the feature by turning off the
- * master location switch, or disabling automatic time zone detection.
- */
- @DeviceConfigKey
- public static final String KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED =
- "force_location_time_zone_detection_enabled";
-
- /**
- * The key for the default value used to determine whether location time zone detection is
- * enabled when the user hasn't explicitly set it yet.
- */
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT =
- "location_time_zone_detection_enabled_default";
-
- /**
- * The key for the minimum delay after location time zone detection has been enabled before the
- * location time zone manager can report it is uncertain about the time zone.
- */
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
- "location_time_zone_detection_uncertainty_delay_millis";
-
- /**
- * The key for the timeout passed to a location time zone provider that tells it how long it has
- * to provide an explicit first suggestion without being declared uncertain.
- */
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
- "ltpz_init_timeout_millis";
-
- /**
- * The key for the extra time added to {@link
- * #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone
- * manager before the location time zone provider will actually be declared uncertain.
- */
- @DeviceConfigKey
- public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
- "ltpz_init_timeout_fuzz_millis";
-
- /** Creates an instance. */
- public DeviceConfig() {}
-
- /** Adds a listener for the system_time namespace. */
- public void addListener(
- @NonNull Executor handlerExecutor, @NonNull Runnable listener) {
- android.provider.DeviceConfig.addOnPropertiesChangedListener(
- NAMESPACE_SYSTEM_TIME,
- handlerExecutor,
- properties -> listener.run());
- }
-
- /**
- * Returns a boolean value from {@link android.provider.DeviceConfig} from the system_time
- * namespace, or {@code defaultValue} if there is no explicit value set.
- */
- public boolean getBoolean(@DeviceConfigKey String key, boolean defaultValue) {
- return android.provider.DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue);
- }
-
- /**
- * Returns a positive duration from {@link android.provider.DeviceConfig} from the system_time
- * namespace, or {@code defaultValue} if there is no explicit value set.
- */
- @Nullable
- public Duration getDurationFromMillis(
- @DeviceConfigKey String key, @Nullable Duration defaultValue) {
- long deviceConfigValue =
- android.provider.DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1);
- if (deviceConfigValue < 0) {
- return defaultValue;
- }
- return Duration.ofMillis(deviceConfigValue);
- }
-}
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
new file mode 100644
index 0000000..8819b37
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -0,0 +1,238 @@
+/*
+ * 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 android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.content.Context;
+import android.provider.DeviceConfig;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
+import com.android.server.timezonedetector.ServiceConfigAccessor;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A helper class for reading / monitoring the {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace
+ * for server-configured flags.
+ */
+public final class ServerFlags {
+
+ private static final Optional<Boolean> OPTIONAL_TRUE = Optional.of(true);
+ private static final Optional<Boolean> OPTIONAL_FALSE = Optional.of(false);
+
+ /**
+ * An annotation used to indicate when a {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} key is
+ * required.
+ *
+ * <p>Note that the com.android.geotz module deployment of the Offline LocationTimeZoneProvider
+ * also shares the {@link DeviceConfig#NAMESPACE_SYSTEM_TIME}, and uses the
+ * prefix "geotz_" on all of its key strings.
+ */
+ @StringDef(prefix = "KEY_", value = {
+ KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+ KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+ KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
+ KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
+ KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+ })
+ @interface DeviceConfigKey {}
+
+ /**
+ * Controls whether the location time zone manager service will started. Only observed if
+ * the device build is configured to support location-based time zone detection. See
+ * {@link ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupportedInConfig()} and {@link
+ * ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupported()}.
+ */
+ @DeviceConfigKey
+ public static final String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED =
+ "location_time_zone_detection_feature_supported";
+
+ /**
+ * The key for the server flag that can override the device config for whether the primary
+ * location time zone provider is enabled or disabled.
+ */
+ @DeviceConfigKey
+ public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
+ "primary_location_time_zone_provider_enabled_override";
+
+ /**
+ * The key for the server flag that can override the device config for whether the secondary
+ * location time zone provider is enabled or disabled.
+ */
+ @DeviceConfigKey
+ public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
+ "secondary_location_time_zone_provider_enabled_override";
+
+ /**
+ * The key for the minimum delay after location time zone detection has been enabled before the
+ * location time zone manager can report it is uncertain about the time zone.
+ */
+ @DeviceConfigKey
+ public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
+ "location_time_zone_detection_uncertainty_delay_millis";
+
+ /**
+ * The key for the timeout passed to a location time zone provider that tells it how long it has
+ * to provide an explicit first suggestion without being declared uncertain.
+ */
+ @DeviceConfigKey
+ public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
+ "ltpz_init_timeout_millis";
+
+ /**
+ * The key for the extra time added to {@link
+ * #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone
+ * manager before the location time zone provider will actually be declared uncertain.
+ */
+ @DeviceConfigKey
+ public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
+ "ltpz_init_timeout_fuzz_millis";
+
+ /**
+ * The key for the server flag that can override location time zone detection being enabled for
+ * a user. Only intended for use during release testing with droidfooders. The user can still
+ * disable the feature by turning off the master location switch, or by disabling automatic time
+ * zone detection.
+ */
+ @DeviceConfigKey
+ public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE =
+ "location_time_zone_detection_setting_enabled_override";
+
+ /**
+ * The key for the default value used to determine whether location time zone detection is
+ * enabled when the user hasn't explicitly set it yet.
+ */
+ @DeviceConfigKey
+ public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT =
+ "location_time_zone_detection_setting_enabled_default";
+
+ @GuardedBy("mListeners")
+ private final ArrayMap<ConfigurationChangeListener, Set<String>> mListeners = new ArrayMap<>();
+
+ private static final Object SLOCK = new Object();
+
+ @GuardedBy("SLOCK")
+ @Nullable
+ private static ServerFlags sInstance;
+
+ private ServerFlags(Context context) {
+ DeviceConfig.addOnPropertiesChangedListener(
+ NAMESPACE_SYSTEM_TIME,
+ context.getMainExecutor(),
+ this::handlePropertiesChanged);
+ }
+
+ /** Returns the singleton instance. */
+ public static ServerFlags getInstance(Context context) {
+ synchronized (SLOCK) {
+ if (sInstance == null) {
+ sInstance = new ServerFlags(context);
+ }
+ return sInstance;
+ }
+ }
+
+ private void handlePropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ synchronized (mListeners) {
+ for (Map.Entry<ConfigurationChangeListener, Set<String>> listenerEntry
+ : mListeners.entrySet()) {
+ if (intersects(listenerEntry.getValue(), properties.getKeyset())) {
+ listenerEntry.getKey().onChange();
+ }
+ }
+ }
+ }
+
+ private static boolean intersects(@NonNull Set<String> one, @NonNull Set<String> two) {
+ for (String toFind : one) {
+ if (two.contains(toFind)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds a listener for the system_time namespace that will trigger if any of the specified keys
+ * change. Listener callbacks are delivered on the main looper thread.
+ *
+ * <p>Note: Only for use by long-lived objects like other singletons. There is deliberately no
+ * associated remove method.
+ */
+ public void addListener(@NonNull ConfigurationChangeListener listener,
+ @NonNull Set<String> keys) {
+ Objects.requireNonNull(listener);
+ Objects.requireNonNull(keys);
+
+ synchronized (mListeners) {
+ mListeners.put(listener, keys);
+ }
+ }
+
+ /**
+ * Returns an optional boolean value from {@link DeviceConfig} from the system_time
+ * namespace, returns {@link Optional#empty()} if there is no explicit value set.
+ */
+ @NonNull
+ public Optional<Boolean> getOptionalBoolean(@DeviceConfigKey String key) {
+ String value = DeviceConfig.getProperty(NAMESPACE_SYSTEM_TIME, key);
+ return parseOptionalBoolean(value);
+ }
+
+ @NonNull
+ private static Optional<Boolean> parseOptionalBoolean(@Nullable String value) {
+ if (value == null) {
+ return Optional.empty();
+ } else {
+ return Boolean.parseBoolean(value) ? OPTIONAL_TRUE : OPTIONAL_FALSE;
+ }
+ }
+
+ /**
+ * Returns a boolean value from {@link DeviceConfig} from the system_time
+ * namespace, or {@code defaultValue} if there is no explicit value set.
+ */
+ public boolean getBoolean(@DeviceConfigKey String key, boolean defaultValue) {
+ return DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue);
+ }
+
+ /**
+ * Returns a positive duration from {@link DeviceConfig} from the system_time
+ * namespace, or {@code defaultValue} if there is no explicit value set.
+ */
+ @Nullable
+ public Duration getDurationFromMillis(
+ @DeviceConfigKey String key, @Nullable Duration defaultValue) {
+ long deviceConfigValue = DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1);
+ if (deviceConfigValue < 0) {
+ return defaultValue;
+ }
+ return Duration.ofMillis(deviceConfigValue);
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
index 4c7b1f3..aa8ad37 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
@@ -17,10 +17,11 @@
package com.android.server.timezonedetector;
/**
- * A listener used to receive notification that time zone configuration has changed.
+ * A listener used to receive notification that configuration has / may have changed (depending on
+ * the usecase).
*/
@FunctionalInterface
public interface ConfigurationChangeListener {
- /** Called when the current user or a configuration value has changed. */
+ /** Called when the configuration may have changed. */
void onChange();
}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 1f73977..3ae9d64 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -33,26 +33,27 @@
import java.util.Objects;
/**
- * Holds all configuration values that affect time zone behavior and some associated logic, e.g.
- * {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link
- * #createCapabilitiesAndConfig()}.
+ * Holds configuration values that affect user-facing time zone behavior and some associated logic.
+ * Some configuration is global, some is user scoped, but this class deliberately doesn't make a
+ * distinction for simplicity.
*/
public final class ConfigurationInternal {
- private final @UserIdInt int mUserId;
- private final boolean mUserConfigAllowed;
private final boolean mAutoDetectionSupported;
private final boolean mGeoDetectionSupported;
private final boolean mAutoDetectionEnabled;
+ private final @UserIdInt int mUserId;
+ private final boolean mUserConfigAllowed;
private final boolean mLocationEnabled;
private final boolean mGeoDetectionEnabled;
private ConfigurationInternal(Builder builder) {
- mUserId = builder.mUserId;
- mUserConfigAllowed = builder.mUserConfigAllowed;
mAutoDetectionSupported = builder.mAutoDetectionSupported;
mGeoDetectionSupported = builder.mGeoDetectionSupported;
mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+
+ mUserId = builder.mUserId;
+ mUserConfigAllowed = builder.mUserConfigAllowed;
mLocationEnabled = builder.mLocationEnabled;
mGeoDetectionEnabled = builder.mGeoDetectionEnabled;
// if mGeoDetectionSupported then mAutoDetectionSupported, i.e. mGeoDetectionSupported
@@ -60,22 +61,6 @@
Preconditions.checkState(mAutoDetectionSupported || !mGeoDetectionSupported);
}
- /** Returns the ID of the user this configuration is associated with. */
- public @UserIdInt int getUserId() {
- return mUserId;
- }
-
- /** Returns the handle of the user this configuration is associated with. */
- @NonNull
- public UserHandle getUserHandle() {
- return UserHandle.of(mUserId);
- }
-
- /** Returns true if the user allowed to modify time zone configuration. */
- public boolean isUserConfigAllowed() {
- return mUserConfigAllowed;
- }
-
/** Returns true if the device supports any form of auto time zone detection. */
public boolean isAutoDetectionSupported() {
return mAutoDetectionSupported;
@@ -98,6 +83,22 @@
return mAutoDetectionSupported && mAutoDetectionEnabled;
}
+ /** Returns the ID of the user this configuration is associated with. */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /** Returns the handle of the user this configuration is associated with. */
+ @NonNull
+ public UserHandle getUserHandle() {
+ return UserHandle.of(mUserId);
+ }
+
+ /** Returns true if the user allowed to modify time zone configuration. */
+ public boolean isUserConfigAllowed() {
+ return mUserConfigAllowed;
+ }
+
/** Returns true if user's location can be used generally. */
public boolean isLocationEnabled() {
return mLocationEnabled;
@@ -283,7 +284,7 @@
/**
* Sets whether any form of automatic time zone detection is supported on this device.
*/
- public Builder setAutoDetectionSupported(boolean supported) {
+ public Builder setAutoDetectionFeatureSupported(boolean supported) {
mAutoDetectionSupported = supported;
return this;
}
@@ -291,7 +292,7 @@
/**
* Sets whether geolocation time zone detection is supported on this device.
*/
- public Builder setGeoDetectionSupported(boolean supported) {
+ public Builder setGeoDetectionFeatureSupported(boolean supported) {
mGeoDetectionSupported = supported;
return this;
}
diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
index f52b9b1..e3caae94 100644
--- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
@@ -31,9 +31,7 @@
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.location.LocationManager;
-import android.net.ConnectivityManager;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -42,10 +40,9 @@
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
-import com.android.server.timedetector.DeviceConfig;
import java.util.Objects;
-import java.util.concurrent.Executor;
+import java.util.Optional;
/**
* The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
@@ -59,8 +56,7 @@
@NonNull private final Handler mHandler;
@NonNull private final ContentResolver mCr;
@NonNull private final UserManager mUserManager;
- @NonNull private final DeviceConfig mDeviceConfig;
- @NonNull private final boolean mGeoDetectionSupported;
+ @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final LocationManager mLocationManager;
// @NonNull after setConfigChangeListener() is called.
@@ -68,17 +64,16 @@
private ConfigurationChangeListener mConfigChangeListener;
EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
- @NonNull DeviceConfig deviceConfig, boolean geoDetectionSupported) {
+ @NonNull ServiceConfigAccessor serviceConfigAccessor) {
mContext = Objects.requireNonNull(context);
mHandler = Objects.requireNonNull(handler);
- Executor handlerExecutor = new HandlerExecutor(mHandler);
mCr = context.getContentResolver();
mUserManager = context.getSystemService(UserManager.class);
mLocationManager = context.getSystemService(LocationManager.class);
- mDeviceConfig = deviceConfig;
- mGeoDetectionSupported = geoDetectionSupported;
+ mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
- // Wire up the change listeners. All invocations are performed on the mHandler thread.
+ // Wire up the config change listeners. All invocations are performed on the mHandler
+ // thread.
// Listen for the user changing / the user's location mode changing.
IntentFilter filter = new IntentFilter();
@@ -112,13 +107,6 @@
handleConfigChangeOnHandlerThread();
}
}, UserHandle.USER_ALL);
-
- // Add async callbacks for changes to server-side flags: some of the flags affect device /
- // user config. All changes can be treated like a config change. If flags that affect config
- // haven't changed then call will be a no-op.
- mDeviceConfig.addListener(
- handlerExecutor,
- this::handleConfigChangeOnHandlerThread);
}
private void handleConfigChangeOnHandlerThread() {
@@ -140,10 +128,12 @@
@Override
public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
return new ConfigurationInternal.Builder(userId)
- .setUserConfigAllowed(isUserConfigAllowed(userId))
- .setAutoDetectionSupported(isAutoDetectionSupported())
- .setGeoDetectionSupported(isGeoDetectionSupported())
+ .setAutoDetectionFeatureSupported(
+ mServiceConfigAccessor.isAutoDetectionFeatureSupported())
+ .setGeoDetectionFeatureSupported(
+ mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported())
.setAutoDetectionEnabled(isAutoDetectionEnabled())
+ .setUserConfigAllowed(isUserConfigAllowed(userId))
.setLocationEnabled(isLocationEnabled(userId))
.setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
.build();
@@ -186,18 +176,19 @@
// time zone detection: if we wrote it down then we'd set the value explicitly, which would
// prevent detecting "default" later. That might influence what happens on later releases
// that support new types of auto detection on the same hardware.
- if (isAutoDetectionSupported()) {
+ if (mServiceConfigAccessor.isAutoDetectionFeatureSupported()) {
final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
setAutoDetectionEnabledIfRequired(autoDetectionEnabled);
- // Avoid writing the geo detection enabled setting for devices that do not support geo
- // time zone detection: if we wrote it down then we'd set the value explicitly, which
- // would prevent detecting "default" later. That might influence what happens on later
- // releases that support geo detection on the same hardware.
- // Also avoid writing the geo detection enabled setting for devices that are currently
- // force-enabled: otherwise we might overwrite a droidfood user's real setting
- // permanently.
- if (isGeoDetectionSupported() && !isGeoDetectionForceEnabled()) {
+ // Avoid writing the geo detection enabled setting for devices with settings that
+ // are currently overridden by server flags: otherwise we might overwrite a droidfood
+ // user's real setting permanently.
+ // Also avoid writing the geo detection enabled setting for devices that do not support
+ // geo time zone detection: if we wrote it down then we'd set the value explicitly,
+ // which would prevent detecting "default" later. That might influence what happens on
+ // later releases that start to support geo detection on the same hardware.
+ if (!mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride().isPresent()
+ && mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) {
final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
setGeoDetectionEnabledIfRequired(userId, geoTzDetectionEnabled);
}
@@ -209,14 +200,6 @@
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
}
- private boolean isAutoDetectionSupported() {
- return deviceHasTelephonyNetwork() || isGeoDetectionSupported();
- }
-
- private boolean isGeoDetectionSupported() {
- return mGeoDetectionSupported;
- }
-
private boolean isAutoDetectionEnabled() {
return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
}
@@ -237,24 +220,20 @@
private boolean isGeoDetectionEnabled(@UserIdInt int userId) {
// We may never use this, but it gives us a way to force location-based time zone detection
- // on for testers (where their other settings allow).
- boolean forceEnabled = isGeoDetectionForceEnabled();
- if (forceEnabled) {
- return true;
+ // on/off for testers (but only where their other settings would allow them to turn it on
+ // for themselves).
+ Optional<Boolean> override = mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride();
+ if (override.isPresent()) {
+ return override.get();
}
- final boolean geoDetectionEnabledByDefault = mDeviceConfig.getBoolean(
- DeviceConfig.KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT, false);
+ final boolean geoDetectionEnabledByDefault =
+ mServiceConfigAccessor.isGeoDetectionEnabledForUsersByDefault();
return Settings.Secure.getIntForUser(mCr,
Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
(geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0;
}
- private boolean isGeoDetectionForceEnabled() {
- return mDeviceConfig.getBoolean(
- DeviceConfig.KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED, false);
- }
-
private void setGeoDetectionEnabledIfRequired(@UserIdInt int userId, boolean enabled) {
// See comment in setAutoDetectionEnabledIfRequired. http://b/171953500
if (isGeoDetectionEnabled(userId) != enabled) {
@@ -262,10 +241,4 @@
enabled ? 1 : 0, userId);
}
}
-
- private boolean deviceHasTelephonyNetwork() {
- // TODO b/150583524 Avoid the use of a deprecated API.
- return mContext.getSystemService(ConnectivityManager.class)
- .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
- }
}
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
new file mode 100644
index 0000000..86c32f8
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -0,0 +1,249 @@
+/*
+ * 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.timezonedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timedetector.ServerFlags;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A singleton that provides access to service configuration for time zone 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.
+ */
+public final class ServiceConfigAccessor {
+
+ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
+ new ArraySet<>(new String[] {
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
+ ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+ ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
+ ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS
+ }));
+
+ // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented
+ private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(1);
+ // TODO(b/179488561): Put this back to 1 minute when primary provider is fully implemented
+ private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ =
+ Duration.ofSeconds(20);
+ private static final Duration DEFAULT_PROVIDER_UNCERTAINTY_DELAY = Duration.ofMinutes(5);
+
+ 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;
+
+ /**
+ * An ultimate "feature switch" for location-based time zone detection. If this is
+ * {@code false}, the device cannot support the feature without a config change or a reboot:
+ * This affects what services are started on boot to minimize expense when the feature is not
+ * wanted.
+ */
+ private final boolean mGeoDetectionFeatureSupportedInConfig;
+
+ @NonNull private final ServerFlags mServerFlags;
+
+ private ServiceConfigAccessor(@NonNull Context context) {
+ mContext = Objects.requireNonNull(context);
+
+ // The config value is expected to be the main feature flag. Platform developers can also
+ // force enable the feature using a persistent system property. Because system properties
+ // can change, this value is cached and only changes on reboot.
+ mGeoDetectionFeatureSupportedInConfig = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection)
+ || SystemProperties.getBoolean(
+ "persist.sys.location_time_zone_detection_feature_supported", false);
+
+ mServerFlags = ServerFlags.getInstance(mContext);
+ }
+
+ /** Returns the singleton instance. */
+ public static ServiceConfigAccessor getInstance(Context context) {
+ synchronized (SLOCK) {
+ if (sInstance == null) {
+ sInstance = new ServiceConfigAccessor(context);
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Adds a listener that will be called 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.
+ */
+ public void addListener(@NonNull ConfigurationChangeListener listener) {
+ mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH);
+ }
+
+ /** Returns {@code true} if any form of automatic time zone detection is supported. */
+ public boolean isAutoDetectionFeatureSupported() {
+ return deviceHasTelephonyNetwork() || isGeoTimeZoneDetectionFeatureSupported();
+ }
+
+ private boolean deviceHasTelephonyNetwork() {
+ // TODO b/150583524 Avoid the use of a deprecated API.
+ return mContext.getSystemService(ConnectivityManager.class)
+ .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ }
+
+ /**
+ * Returns {@code true} if the location-based time zone detection feature can be supported on
+ * this device at all according to config. When {@code false}, implies that various other
+ * location-based settings will be turned off or rendered meaningless. Typically {@link
+ * #isGeoTimeZoneDetectionFeatureSupported()} should be used instead.
+ */
+ public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() {
+ return mGeoDetectionFeatureSupportedInConfig;
+ }
+
+ /**
+ * Returns {@code true} if the location-based time zone detection feature is supported on the
+ * device. This can be used during feature testing on builds that are capable of location time
+ * zone detection to enable / disable the feature for some users.
+ */
+ public boolean isGeoTimeZoneDetectionFeatureSupported() {
+ return mGeoDetectionFeatureSupportedInConfig
+ && isGeoTimeZoneDetectionFeatureSupportedInternal();
+ }
+
+ private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() {
+ final boolean defaultEnabled = true;
+ return mServerFlags.getBoolean(
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+ defaultEnabled);
+ }
+
+ /**
+ * Returns {@code true} if the primary location time zone provider can be used.
+ */
+ public boolean isPrimaryLocationTimeZoneProviderEnabled() {
+ return getPrimaryLocationTimeZoneProviderEnabledOverride()
+ .orElse(isPrimaryLocationTimeZoneProviderEnabledInConfig());
+ }
+
+ private boolean isPrimaryLocationTimeZoneProviderEnabledInConfig() {
+ int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
+ return getConfigBoolean(providerEnabledConfigId);
+ }
+
+ @NonNull
+ private Optional<Boolean> getPrimaryLocationTimeZoneProviderEnabledOverride() {
+ return mServerFlags.getOptionalBoolean(
+ ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+ }
+
+ /**
+ * Returns {@code true} if the secondary location time zone provider can be used.
+ */
+ public boolean isSecondaryLocationTimeZoneProviderEnabled() {
+ return getSecondaryLocationTimeZoneProviderEnabledOverride()
+ .orElse(isSecondaryLocationTimeZoneProviderEnabledInConfig());
+ }
+
+ private boolean isSecondaryLocationTimeZoneProviderEnabledInConfig() {
+ int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
+ return getConfigBoolean(providerEnabledConfigId);
+ }
+
+ @NonNull
+ private Optional<Boolean> getSecondaryLocationTimeZoneProviderEnabledOverride() {
+ return mServerFlags.getOptionalBoolean(
+ ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+ }
+
+ /**
+ * Returns whether location time zone detection is enabled for users when there's no setting
+ * value. Intended for use during feature release testing to "opt-in" users that haven't shown
+ * an explicit preference.
+ */
+ public boolean isGeoDetectionEnabledForUsersByDefault() {
+ return mServerFlags.getBoolean(
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, false);
+ }
+
+ /**
+ * Returns whether location time zone detection is force enabled/disabled for users. Intended
+ * for use during feature release testing to force a given state.
+ */
+ @NonNull
+ public Optional<Boolean> getGeoDetectionSettingEnabledOverride() {
+ return mServerFlags.getOptionalBoolean(
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
+ }
+
+ /**
+ * Returns the time to send to a location time zone provider that informs it how long it has
+ * to return its first time zone suggestion.
+ */
+ @NonNull
+ public Duration getLocationTimeZoneProviderInitializationTimeout() {
+ return mServerFlags.getDurationFromMillis(
+ ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
+ DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT);
+ }
+
+ /**
+ * Returns the time added to {@link #getLocationTimeZoneProviderInitializationTimeout()} by the
+ * server before unilaterally declaring the provider is uncertain.
+ */
+ @NonNull
+ public Duration getLocationTimeZoneProviderInitializationTimeoutFuzz() {
+ return mServerFlags.getDurationFromMillis(
+ ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+ DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ);
+ }
+
+ /**
+ * Returns the time after uncertainty is detected by providers before the location time zone
+ * manager makes a suggestion to the time zone detector.
+ */
+ @NonNull
+ public Duration getLocationTimeZoneUncertaintyDelay() {
+ return mServerFlags.getDurationFromMillis(
+ ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
+ DEFAULT_PROVIDER_UNCERTAINTY_DELAY);
+ }
+
+ private boolean getConfigBoolean(int providerEnabledConfigId) {
+ Resources resources = mContext.getResources();
+ return resources.getBoolean(providerEnabledConfigId);
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index 203a8a4..cd220b1 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -27,16 +27,21 @@
*/
public interface TimeZoneDetectorInternal extends Dumpable.Container {
- /** Adds a listener that will be invoked when time zone detection configuration is changed. */
- void addConfigurationListener(ConfigurationChangeListener listener);
+ /** Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed. */
+ void addConfigurationListener(@NonNull ConfigurationChangeListener listener);
/**
* Removes a listener previously added via {@link
* #addConfigurationListener(ConfigurationChangeListener)}.
*/
- void removeConfigurationListener(ConfigurationChangeListener listener);
+ void removeConfigurationListener(@NonNull ConfigurationChangeListener listener);
- /** Returns the {@link ConfigurationInternal} for the current user. */
+ /**
+ * Returns a snapshot of the {@link ConfigurationInternal} for the current user. This is only a
+ * snapshot so callers must use {@link #addConfigurationListener(ConfigurationChangeListener)}
+ * to be notified when it changes.
+ */
+ @NonNull
ConfigurationInternal getCurrentUserConfigurationInternal();
/**
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index bd71ddf..c20400a 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -33,7 +33,6 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -62,27 +61,6 @@
static final String TAG = "time_zone_detector";
/**
- * A "feature switch" for location-based time zone detection. If this is {@code false}. It is
- * initialized and never refreshed; it affects what services are started on boot so consistency
- * is important.
- */
- @Nullable
- private static Boolean sGeoLocationTimeZoneDetectionSupported;
-
- /** Returns {@code true} if the location-based time zone detection feature is enabled. */
- public static boolean isGeoLocationTimeZoneDetectionSupported(Context context) {
- if (sGeoLocationTimeZoneDetectionSupported == null) {
- // The config value is expected to be the main switch. Platform developers can also
- // enable the feature using a persistent system property.
- sGeoLocationTimeZoneDetectionSupported = context.getResources().getBoolean(
- com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection)
- || SystemProperties.getBoolean(
- "persist.sys.location_time_zone_detection_feature_enabled", false);
- }
- return sGeoLocationTimeZoneDetectionSupported;
- }
-
- /**
* Handles the service lifecycle for {@link TimeZoneDetectorService} and
* {@link TimeZoneDetectorInternalImpl}.
*/
@@ -98,11 +76,10 @@
Context context = getContext();
Handler handler = FgThread.getHandler();
- boolean geolocationTimeZoneDetectionSupported =
- isGeoLocationTimeZoneDetectionSupported(context);
+ ServiceConfigAccessor serviceConfigAccessor =
+ ServiceConfigAccessor.getInstance(context);
TimeZoneDetectorStrategy timeZoneDetectorStrategy =
- TimeZoneDetectorStrategyImpl.create(
- context, handler, geolocationTimeZoneDetectionSupported);
+ TimeZoneDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
// Create and publish the local service for use by internal callers.
TimeZoneDetectorInternal internal =
@@ -330,7 +307,8 @@
boolean isGeoTimeZoneDetectionSupported() {
enforceManageTimeZoneDetectorPermission();
- return isGeoLocationTimeZoneDetectionSupported(mContext);
+ return ServiceConfigAccessor.getInstance(mContext)
+ .isGeoTimeZoneDetectionFeatureSupported();
}
@Override
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 0b1d6d7..8266f12 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -75,17 +75,21 @@
public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
/**
- * Sets a listener that will be triggered whenever time zone detection configuration is
+ * Adds a listener that will be triggered whenever {@link ConfigurationInternal} may have
* changed.
*/
void addConfigChangeListener(@NonNull ConfigurationChangeListener listener);
- /** Returns the user's time zone configuration. */
+ /**
+ * Returns a snapshot of the configuration that controls time zone detector behavior for the
+ * specified user.
+ */
@NonNull
ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
/**
- * Returns the configuration that controls time zone detector behavior for the current user.
+ * Returns a snapshot of the configuration that controls time zone detector behavior for the
+ * current user.
*/
@NonNull
ConfigurationInternal getCurrentUserConfigurationInternal();
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index c464b74..d163a0e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -38,7 +38,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.timedetector.DeviceConfig;
import java.util.ArrayList;
import java.util.List;
@@ -204,11 +203,9 @@
*/
public static TimeZoneDetectorStrategyImpl create(
@NonNull Context context, @NonNull Handler handler,
- boolean geoDetectionSupported) {
+ @NonNull ServiceConfigAccessor serviceConfigAccessor) {
- DeviceConfig deviceConfig = new DeviceConfig();
- EnvironmentImpl environment = new EnvironmentImpl(
- context, handler, deviceConfig, geoDetectionSupported);
+ Environment environment = new EnvironmentImpl(context, handler, serviceConfigAccessor);
return new TimeZoneDetectorStrategyImpl(environment);
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
index e463ee2..98e984d 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
@@ -19,9 +19,9 @@
import android.annotation.NonNull;
import com.android.server.LocalServices;
-import com.android.server.timedetector.DeviceConfig;
import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ConfigurationInternal;
+import com.android.server.timezonedetector.ServiceConfigAccessor;
import com.android.server.timezonedetector.TimeZoneDetectorInternal;
import java.time.Duration;
@@ -33,28 +33,19 @@
*/
class ControllerEnvironmentImpl extends LocationTimeZoneProviderController.Environment {
- // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented
- private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(1);
- // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented
- private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ =
- Duration.ofSeconds(20);
- private static final Duration DEFAULT_PROVIDER_UNCERTAINTY_DELAY = Duration.ofMinutes(5);
-
@NonNull private final TimeZoneDetectorInternal mTimeZoneDetectorInternal;
- @NonNull private final LocationTimeZoneProviderController mController;
- @NonNull private final DeviceConfig mDeviceConfig;
+ @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final ConfigurationChangeListener mConfigurationChangeListener;
ControllerEnvironmentImpl(@NonNull ThreadingDomain threadingDomain,
- @NonNull DeviceConfig deviceConfig,
+ @NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull LocationTimeZoneProviderController controller) {
super(threadingDomain);
- mController = Objects.requireNonNull(controller);
- mDeviceConfig = Objects.requireNonNull(deviceConfig);
+ mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
mTimeZoneDetectorInternal = LocalServices.getService(TimeZoneDetectorInternal.class);
// Listen for configuration changes.
- mConfigurationChangeListener = () -> mThreadingDomain.post(mController::onConfigChanged);
+ mConfigurationChangeListener = () -> mThreadingDomain.post(controller::onConfigChanged);
mTimeZoneDetectorInternal.addConfigurationListener(mConfigurationChangeListener);
}
@@ -73,24 +64,18 @@
@Override
@NonNull
Duration getProviderInitializationTimeout() {
- return mDeviceConfig.getDurationFromMillis(
- DeviceConfig.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
- DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT);
+ return mServiceConfigAccessor.getLocationTimeZoneProviderInitializationTimeout();
}
@Override
@NonNull
Duration getProviderInitializationTimeoutFuzz() {
- return mDeviceConfig.getDurationFromMillis(
- DeviceConfig.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
- DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ);
+ return mServiceConfigAccessor.getLocationTimeZoneProviderInitializationTimeoutFuzz();
}
@Override
@NonNull
Duration getUncertaintyDelay() {
- return mDeviceConfig.getDurationFromMillis(
- DeviceConfig.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
- DEFAULT_PROVIDER_UNCERTAINTY_DELAY);
+ return mServiceConfigAccessor.getLocationTimeZoneUncertaintyDelay();
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index 364eaf8..0d1692a 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -21,11 +21,11 @@
import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
+import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -43,9 +43,8 @@
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.SystemService;
-import com.android.server.timedetector.DeviceConfig;
+import com.android.server.timezonedetector.ServiceConfigAccessor;
import com.android.server.timezonedetector.TimeZoneDetectorInternal;
-import com.android.server.timezonedetector.TimeZoneDetectorService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -96,28 +95,31 @@
private LocationTimeZoneManagerService mService;
+ @NonNull
+ private final ServiceConfigAccessor mServerConfigAccessor;
+
public Lifecycle(@NonNull Context context) {
super(Objects.requireNonNull(context));
+ mServerConfigAccessor = ServiceConfigAccessor.getInstance(context);
}
@Override
public void onStart() {
Context context = getContext();
- if (TimeZoneDetectorService.isGeoLocationTimeZoneDetectionSupported(context)) {
+ if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
mService = new LocationTimeZoneManagerService(context);
// The service currently exposes no LocalService or Binder API, but it extends
// Binder and is registered as a binder service so it can receive shell commands.
- publishBinderService("location_time_zone_manager", mService);
+ publishBinderService(SERVICE_NAME, mService);
} else {
- Slog.i(TAG, getClass() + " is disabled");
+ Slog.d(TAG, "Geo time zone detection feature is disabled in config");
}
}
@Override
- public void onBootPhase(int phase) {
- Context context = getContext();
- if (TimeZoneDetectorService.isGeoLocationTimeZoneDetectionSupported(context)) {
+ public void onBootPhase(@BootPhase int phase) {
+ if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
// The location service must be functioning after this boot phase.
mService.onSystemReady();
@@ -159,6 +161,9 @@
/** The shared lock from {@link #mThreadingDomain}. */
@NonNull private final Object mSharedLock;
+ @NonNull
+ private final ServiceConfigAccessor mServiceConfigAccessor;
+
// Lazily initialized. Can be null if the service has been stopped.
@GuardedBy("mSharedLock")
private ControllerImpl mLocationTimeZoneDetectorController;
@@ -180,24 +185,38 @@
mHandler = FgThread.getHandler();
mThreadingDomain = new HandlerThreadingDomain(mHandler);
mSharedLock = mThreadingDomain.getLockObject();
+ mServiceConfigAccessor = ServiceConfigAccessor.getInstance(mContext);
}
+ // According to the SystemService docs: All lifecycle methods are called from the system
+ // server's main looper thread.
void onSystemReady() {
- // Called on an arbitrary thread during initialization.
- synchronized (mSharedLock) {
- // TODO(b/152744911): LocationManagerService watches for packages disappearing. Need to
- // do anything here?
+ mServiceConfigAccessor.addListener(this::handleServiceConfigurationChangedOnMainThread);
+ }
- // TODO(b/152744911): LocationManagerService watches for foreground app changes. Need to
- // do anything here?
- // TODO(b/152744911): LocationManagerService watches screen state. Need to do anything
- // here?
+ private void handleServiceConfigurationChangedOnMainThread() {
+ // This method is called on the main thread, but service logic takes place on the threading
+ // domain thread, so we post the work there.
+
+ // The way all service-level configuration changes are handled is to just restart this
+ // service - this is simple and effective, and service configuration changes should be rare.
+ mThreadingDomain.post(this::restartIfRequiredOnDomainThread);
+ }
+
+ private void restartIfRequiredOnDomainThread() {
+ mThreadingDomain.assertCurrentThread();
+
+ synchronized (mSharedLock) {
+ // Stop and start the service, waiting until completion.
+ stopOnDomainThread();
+ startOnDomainThread();
}
}
+ // According to the SystemService docs: All lifecycle methods are called from the system
+ // server's main looper thread.
void onSystemThirdPartyAppsCanStart() {
- // Called on an arbitrary thread during initialization. We do not want to wait for
- // completion as it would delay boot.
+ // Do not wait for completion as it would delay boot.
final boolean waitForCompletion = false;
startInternal(waitForCompletion);
}
@@ -205,6 +224,9 @@
/**
* Starts the service during server initialization or during tests after a call to
* {@link #stop()}.
+ *
+ * <p>Because this method posts work to the {@code mThreadingDomain} thread and waits for
+ * completion, it cannot be called from the {@code mThreadingDomain} thread.
*/
void start() {
enforceManageTimeZoneDetectorPermission();
@@ -214,28 +236,17 @@
}
/**
- * Starts the service during server initialization or during tests after a call to
- * {@link #stop()}.
+ * Starts the service during server initialization, if the configuration changes or during tests
+ * after a call to {@link #stop()}.
*
* <p>To avoid tests needing to sleep, when {@code waitForCompletion} is {@code true}, this
* method will not return until all the system server components have started.
+ *
+ * <p>Because this method posts work to the {@code mThreadingDomain} thread, it cannot be
+ * called from the {@code mThreadingDomain} thread when {@code waitForCompletion} is true.
*/
private void startInternal(boolean waitForCompletion) {
- Runnable runnable = () -> {
- synchronized (mSharedLock) {
- if (mLocationTimeZoneDetectorController == null) {
- LocationTimeZoneProvider primary = createPrimaryProvider();
- LocationTimeZoneProvider secondary = createSecondaryProvider();
- mLocationTimeZoneDetectorController =
- new ControllerImpl(mThreadingDomain, primary, secondary);
- DeviceConfig deviceConfig = new DeviceConfig();
- mEnvironment = new ControllerEnvironmentImpl(
- mThreadingDomain, deviceConfig, mLocationTimeZoneDetectorController);
- ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain);
- mLocationTimeZoneDetectorController.initialize(mEnvironment, callback);
- }
- }
- };
+ Runnable runnable = this::startOnDomainThread;
if (waitForCompletion) {
mThreadingDomain.postAndWait(runnable, BLOCKING_OP_WAIT_DURATION_MILLIS);
} else {
@@ -243,11 +254,38 @@
}
}
+ private void startOnDomainThread() {
+ mThreadingDomain.assertCurrentThread();
+
+ synchronized (mSharedLock) {
+ if (!mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) {
+ debugLog("Not starting " + SERVICE_NAME + ": it is disabled in service config");
+ return;
+ }
+
+ if (mLocationTimeZoneDetectorController == null) {
+ LocationTimeZoneProvider primary = createPrimaryProvider();
+ LocationTimeZoneProvider secondary = createSecondaryProvider();
+
+ ControllerImpl controller =
+ new ControllerImpl(mThreadingDomain, primary, secondary);
+ ControllerEnvironmentImpl environment = new ControllerEnvironmentImpl(
+ mThreadingDomain, mServiceConfigAccessor, controller);
+ ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain);
+ controller.initialize(environment, callback);
+
+ mEnvironment = environment;
+ mLocationTimeZoneDetectorController = controller;
+ }
+ }
+ }
+
+ @NonNull
private LocationTimeZoneProvider createPrimaryProvider() {
LocationTimeZoneProviderProxy proxy;
if (isProviderInSimulationMode(PRIMARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (isProviderDisabled(PRIMARY_PROVIDER_NAME)) {
+ } else if (!isProviderEnabled(PRIMARY_PROVIDER_NAME)) {
proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
proxy = new RealLocationTimeZoneProviderProxy(
@@ -262,11 +300,12 @@
return new BinderLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
}
+ @NonNull
private LocationTimeZoneProvider createSecondaryProvider() {
LocationTimeZoneProviderProxy proxy;
if (isProviderInSimulationMode(SECONDARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (isProviderDisabled(SECONDARY_PROVIDER_NAME)) {
+ } else if (!isProviderEnabled(SECONDARY_PROVIDER_NAME)) {
proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
proxy = new RealLocationTimeZoneProviderProxy(
@@ -282,33 +321,27 @@
}
/** Used for bug triage and in tests to simulate provider events. */
- private boolean isProviderInSimulationMode(String providerName) {
+ private boolean isProviderInSimulationMode(@NonNull String providerName) {
return isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_SIMULATED);
}
- /** Used for bug triage, tests and experiments to remove a provider. */
- private boolean isProviderDisabled(String providerName) {
- return !isProviderEnabledInConfig(providerName)
- || isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED);
- }
+ /** Used for bug triage, and by tests and experiments to remove a provider. */
+ private boolean isProviderEnabled(@NonNull String providerName) {
+ if (isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED)) {
+ return false;
+ }
- private boolean isProviderEnabledInConfig(String providerName) {
- int providerEnabledConfigId;
switch (providerName) {
case PRIMARY_PROVIDER_NAME: {
- providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
- break;
+ return mServiceConfigAccessor.isPrimaryLocationTimeZoneProviderEnabled();
}
case SECONDARY_PROVIDER_NAME: {
- providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
- break;
+ return mServiceConfigAccessor.isSecondaryLocationTimeZoneProviderEnabled();
}
default: {
throw new IllegalArgumentException(providerName);
}
}
- Resources resources = mContext.getResources();
- return resources.getBoolean(providerEnabledConfigId);
}
private boolean isProviderModeOverrideSet(@NonNull String providerName, @NonNull String mode) {
@@ -326,22 +359,29 @@
}
/**
- * Stops the service for tests. To avoid tests needing to sleep, this method will not return
- * until all the system server components have stopped.
+ * Stops the service for tests and other rare cases. To avoid tests needing to sleep, this
+ * method will not return until all the system server components have stopped.
+ *
+ * <p>Because this method posts work to the {@code mThreadingDomain} thread and waits it cannot
+ * be called from the {@code mThreadingDomain} thread.
*/
void stop() {
enforceManageTimeZoneDetectorPermission();
- mThreadingDomain.postAndWait(() -> {
- synchronized (mSharedLock) {
- if (mLocationTimeZoneDetectorController != null) {
- mLocationTimeZoneDetectorController.destroy();
- mLocationTimeZoneDetectorController = null;
- mEnvironment.destroy();
- mEnvironment = null;
- }
+ mThreadingDomain.postAndWait(this::stopOnDomainThread, BLOCKING_OP_WAIT_DURATION_MILLIS);
+ }
+
+ private void stopOnDomainThread() {
+ mThreadingDomain.assertCurrentThread();
+
+ synchronized (mSharedLock) {
+ if (mLocationTimeZoneDetectorController != null) {
+ mLocationTimeZoneDetectorController.destroy();
+ mLocationTimeZoneDetectorController = null;
+ mEnvironment.destroy();
+ mEnvironment = null;
}
- }, BLOCKING_OP_WAIT_DURATION_MILLIS);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
index b53150c..bdf4a70 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
@@ -21,6 +21,7 @@
import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
+import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND;
@@ -102,7 +103,7 @@
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
- pw.println("Location Time Zone Manager (location_time_zone_manager) commands for tests:");
+ pw.printf("Location Time Zone Manager (%s) commands for tests:\n", SERVICE_NAME);
pw.println(" help");
pw.println(" Print this help text.");
pw.printf(" %s\n", SHELL_COMMAND_START);
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
index 38211ef..531c62c 100644
--- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
@@ -25,7 +25,6 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -41,6 +40,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.server.ServiceWatcher;
+import com.android.server.ServiceWatcher.BoundService;
import java.util.Objects;
import java.util.function.Predicate;
@@ -123,7 +123,7 @@
return resolves;
}
- private void onBind(IBinder binder, ComponentName componentName) {
+ private void onBind(IBinder binder, BoundService boundService) {
mThreadingDomain.assertCurrentThread();
synchronized (mSharedLock) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java
index 1482031..e8386bc 100644
--- a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java
+++ b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java
@@ -63,8 +63,6 @@
return mSendUpdates;
}
- // TODO(b/152744911) - once there are a couple of implementations, decide whether this needs to
- // be passed to the TimeZoneProviderService and remove if it is not useful.
/**
* Returns the maximum time that the provider is allowed to initialize before it is expected to
* send an event of any sort. Only valid when {@link #sendUpdates()} is {@code true}. Failure to
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 151895f..c830ba9 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -808,7 +808,7 @@
if (rootTask.inFreeformWindowingMode()) {
rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- } else if (!mService.mSizeCompatFreeform && r.inSizeCompatMode()) {
+ } else if (!mService.mSupportsNonResizableMultiWindow && r.inSizeCompatMode()) {
throw new IllegalStateException("Size-compat windows are currently not"
+ "freeform-enabled");
} else if (rootTask.getParent().inFreeformWindowingMode()) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dd9619a..33abcb4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -40,8 +40,11 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.app.servertransaction.TransferSplashScreenViewStateItem.ATTACH_TO;
import static android.app.servertransaction.TransferSplashScreenViewStateItem.HANDOVER_TO;
import static android.content.Intent.ACTION_MAIN;
@@ -209,6 +212,7 @@
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_SOLID_COLOR;
+import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
@@ -557,7 +561,7 @@
/**
* The precomputed display insets for resolving configuration. It will be non-null if
- * {@link #shouldUseSizeCompatMode} returns {@code true}.
+ * {@link #shouldCreateCompatDisplayInsets} returns {@code true}.
*/
private CompatDisplayInsets mCompatDisplayInsets;
@@ -648,6 +652,18 @@
*/
private Rect mSizeCompatBounds;
+ // Whether this activity is in size compatibility mode because its bounds don't fit in parent
+ // naturally.
+ private boolean mInSizeCompatModeForBounds = false;
+
+ // Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
+ // orientation then aspect ratio restrictions are also already respected.
+ // This happens when an activity has fixed orientation which doesn't match orientation of the
+ // parent because a display is ignoring orientation request or fixed to user rotation.
+ // See WindowManagerService#getIgnoreOrientationRequest and
+ // WindowManagerService#getFixedToUserRotation for more context.
+ private boolean mIsLetterboxedForFixedOrientationAndAspectRatio = false;
+
// activity is not displayed?
// TODO: rename to mNoDisplay
@VisibleForTesting
@@ -747,6 +763,10 @@
// Token for targeting this activity for assist purposes.
final Binder assistToken = new Binder();
+ // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be used
+ // without security checks
+ final Binder shareableActivityToken = new Binder();
+
// Tracking cookie for the launch of this activity and it's task.
IBinder mLaunchCookie;
@@ -1296,9 +1316,6 @@
// TODO(b/36505427): Maybe this call should be moved inside
// updateOverrideConfiguration()
newTask.updateOverrideConfigurationFromLaunchBounds();
- // Make sure override configuration is up-to-date before using to create window
- // controller.
- updateSizeCompatMode();
// When an activity is started directly into a split-screen fullscreen root task, we
// need to update the initial multi-window modes so that the callbacks are scheduled
// correctly when the user leaves that mode.
@@ -2549,9 +2566,7 @@
* root task.
*/
boolean supportsFreeform() {
- return mAtmService.mSupportsFreeformWindowManagement
- // Either the activity is resizable, or we allow size compat in freeform.
- && (supportsMultiWindow() || mAtmService.mSizeCompatFreeform);
+ return mAtmService.mSupportsFreeformWindowManagement && supportsMultiWindow();
}
/**
@@ -6718,12 +6733,8 @@
}
if (onDescendantOrientationChanged(this)) {
- // The app is just becoming visible, and the parent Task has updated with the
- // orientation request. Update the size compat mode.
- updateSizeCompatMode();
- // WM Shell can override WM Core positioning (e.g. for letterboxing) so ensure
- // that WM Shell is called when an activity becomes visible. Without this, WM Core
- // will handle positioning instead of WM Shell when an app is reopened.
+ // WM Shell can show additional UI elements, e.g. a restart button for size compat mode
+ // so ensure that WM Shell is called when an activity becomes visible.
task.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
}
}
@@ -6788,7 +6799,10 @@
* density than its parent or its bounds don't fit in parent naturally.
*/
boolean inSizeCompatMode() {
- if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode()
+ if (mInSizeCompatModeForBounds) {
+ return true;
+ }
+ if (mCompatDisplayInsets == null || !shouldCreateCompatDisplayInsets()
// The orientation is different from parent when transforming.
|| isFixedRotationTransforming()) {
return false;
@@ -6798,70 +6812,30 @@
// The app bounds hasn't been computed yet.
return false;
}
-
final Configuration parentConfig = getParent().getConfiguration();
// Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
// fields should be changed with density and bounds, so here only compares the most
// significant field.
- if (parentConfig.densityDpi != getConfiguration().densityDpi) {
- return true;
- }
-
- final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
- final int appWidth = appBounds.width();
- final int appHeight = appBounds.height();
- final int parentAppWidth = parentAppBounds.width();
- final int parentAppHeight = parentAppBounds.height();
- if (parentAppWidth == appWidth && parentAppHeight == appHeight) {
- // Matched the parent bounds.
- return false;
- }
- if (parentAppWidth > appWidth && parentAppHeight > appHeight) {
- // Both sides are smaller than the parent.
- return true;
- }
- if (parentAppWidth < appWidth || parentAppHeight < appHeight) {
- // One side is larger than the parent.
- return true;
- }
-
- // The rest of the condition is that only one side is smaller than the parent, but it still
- // needs to exclude the cases where the size is limited by the fixed aspect ratio.
- if (info.maxAspectRatio > 0) {
- final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
- / Math.min(appWidth, appHeight);
- if (aspectRatio >= info.maxAspectRatio) {
- // The current size has reached the max aspect ratio.
- return false;
- }
- }
- if (info.minAspectRatio > 0) {
- // The activity should have at least the min aspect ratio, so this checks if the parent
- // still has available space to provide larger aspect ratio.
- final float parentAspectRatio = (0.5f + Math.max(parentAppWidth, parentAppHeight))
- / Math.min(parentAppWidth, parentAppHeight);
- if (parentAspectRatio <= info.minAspectRatio) {
- // The long side has reached the parent.
- return false;
- }
- }
- return true;
+ return parentConfig.densityDpi != getConfiguration().densityDpi;
}
/**
* Indicates the activity will keep the bounds and screen configuration when it was first
* launched, no matter how its parent changes.
*
+ * <p>If {@true}, then {@link CompatDisplayInsets} will be created in {@link
+ * #resolveOverrideConfiguration} to "freeze" activity bounds and insets.
+ *
* @return {@code true} if this activity is declared as non-resizable and fixed orientation or
* aspect ratio.
*/
- boolean shouldUseSizeCompatMode() {
+ boolean shouldCreateCompatDisplayInsets() {
if (info.supportsSizeChanges() != ActivityInfo.SIZE_CHANGES_UNSUPPORTED) {
return false;
}
if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) {
final ActivityRecord root = task != null ? task.getRootActivity() : null;
- if (root != null && root != this && !root.shouldUseSizeCompatMode()) {
+ if (root != null && root != this && !root.shouldCreateCompatDisplayInsets()) {
// If the root activity doesn't use size compatibility mode, the activities above
// are forced to be the same for consistent visual appearance.
return false;
@@ -6883,25 +6857,11 @@
}
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
- private void updateSizeCompatMode() {
- if (mCompatDisplayInsets != null || !shouldUseSizeCompatMode()) {
+ private void updateCompatDisplayInsets(@Nullable Rect fixedOrientationBounds) {
+ if (mCompatDisplayInsets != null || !shouldCreateCompatDisplayInsets()) {
// The override configuration is set only once in size compatibility mode.
return;
}
- final Configuration parentConfig = getParent().getConfiguration();
- if (!hasProcess() && !isConfigurationCompatible(parentConfig)) {
- // Don't compute when launching in fullscreen and the fixed orientation is not the
- // current orientation. It is more accurately to compute the override bounds from
- // the updated configuration after the fixed orientation is applied.
- return;
- }
-
- if (task == null || (!handlesOrientationChangeFromDescendant()
- && task.getLastTaskBoundsComputeActivity() != this)) {
- // Don't compute when Task hasn't computed its bounds for this app, because the Task can
- // be letterboxed, and its bounds may not be accurate until then.
- return;
- }
Configuration overrideConfig = getRequestedOverrideConfiguration();
final Configuration fullConfig = getConfiguration();
@@ -6924,17 +6884,18 @@
}
// The role of CompatDisplayInsets is like the override bounds.
- mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this);
+ mCompatDisplayInsets =
+ new CompatDisplayInsets(mDisplayContent, this, fixedOrientationBounds);
}
@VisibleForTesting
void clearSizeCompatMode() {
+ mInSizeCompatModeForBounds = false;
mSizeCompatScale = 1f;
mSizeCompatBounds = null;
mCompatDisplayInsets = null;
- // Recompute from Task because letterbox can also happen on Task level.
- task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration());
+ onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
}
@Override
@@ -6969,23 +6930,41 @@
mTmpConfig.updateFrom(resolvedConfig);
newParentConfiguration = mTmpConfig;
}
+
+ final int windowingMode = getWindowingMode();
+ // TODO(b/181207944): Consider removing the if condition and always run
+ // resolveFixedOrientationConfiguration() since this should be applied for all cases.
+ if (isSplitScreenWindowingMode(windowingMode)
+ || windowingMode == WINDOWING_MODE_MULTI_WINDOW
+ || windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ resolveFixedOrientationConfiguration(newParentConfiguration);
+ }
+ final Rect fixedOrientationBounds = isLetterboxedForFixedOrientationAndAspectRatio()
+ ? new Rect(resolvedConfig.windowConfiguration.getBounds()) : null;
+
if (mCompatDisplayInsets != null) {
resolveSizeCompatModeConfiguration(newParentConfiguration);
- } else {
- if (inMultiWindowMode()) {
- // We ignore activities' requested orientation in multi-window modes. Task level may
- // take them into consideration when calculating bounds.
- resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
- // If the activity has requested override bounds, the configuration needs to be
- // computed accordingly.
- if (!matchParentBounds()) {
- task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
- }
- } else {
- resolveFullscreenConfiguration(newParentConfiguration);
+ } else if (inMultiWindowMode()) {
+ // We ignore activities' requested orientation in multi-window modes. They may be
+ // taken into consideration in resolveFixedOrientationConfiguration call above.
+ resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
+ // If the activity has requested override bounds, the configuration needs to be
+ // computed accordingly.
+ if (!matchParentBounds()) {
+ task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
}
+ // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
+ // are already calculated in resolveFixedOrientationConfiguration.
+ } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) {
+ resolveFullscreenConfiguration(newParentConfiguration);
}
+ if (mVisibleRequested) {
+ updateCompatDisplayInsets(fixedOrientationBounds);
+ }
+
+ // 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.
@@ -6994,6 +6973,109 @@
}
/**
+ * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
+ * orientation then aspect ratio restrictions are also already respected.
+ *
+ * <p>This happens when an activity has fixed orientation which doesn't match orientation of the
+ * parent because a display setting 'ignoreOrientationRequest' is set to true. See {@link
+ * WindowManagerService#getIgnoreOrientationRequest} for more context.
+ */
+ boolean isLetterboxedForFixedOrientationAndAspectRatio() {
+ return mIsLetterboxedForFixedOrientationAndAspectRatio;
+ }
+
+ /**
+ * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation
+ * change and the requested orientation is different from the parent.
+ *
+ * <p>If letterboxed due to fixed orientation then aspect ratio restrictions are also applied
+ * in this methiod.
+ */
+ private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) {
+ mIsLetterboxedForFixedOrientationAndAspectRatio = false;
+ if (handlesOrientationChangeFromDescendant()) {
+ // No need to letterbox because of fixed orientation. Display will handle
+ // fixed-orientation requests.
+ return;
+ }
+
+ final Rect resolvedBounds =
+ getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+ final int parentOrientation = newParentConfig.orientation;
+
+ // If the activity requires a different orientation (either by override or activityInfo),
+ // make it fit the available bounds by scaling down its bounds.
+ final int forcedOrientation = getRequestedConfigurationOrientation();
+ if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
+ return;
+ }
+
+ if (mCompatDisplayInsets != null && !mCompatDisplayInsets.mIsInFixedOrientationLetterbox) {
+ // App prefers to keep its original size.
+ // If the size compat is from previous fixed orientation letterboxing, we may want to
+ // have fixed orientation letterbox again, otherwise it will show the size compat
+ // restart button even if the restart bounds will be the same.
+ return;
+ }
+
+ final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
+ final int parentWidth = parentBounds.width();
+ final int parentHeight = parentBounds.height();
+ float aspect = Math.max(parentWidth, parentHeight)
+ / (float) Math.min(parentWidth, parentHeight);
+
+ // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
+ // order to use the extra available space.
+ final float maxAspectRatio = info.maxAspectRatio;
+ final float minAspectRatio = info.minAspectRatio;
+ if (aspect > maxAspectRatio && maxAspectRatio != 0) {
+ aspect = maxAspectRatio;
+ } else if (aspect < minAspectRatio) {
+ aspect = minAspectRatio;
+ }
+
+ // Override from config_letterboxAspectRatio or via ADB with set-letterbox-aspect-ratio.
+ // TODO(b/175212232): Rename getTaskLetterboxAspectRatio and all related methods since fixed
+ // orientation letterbox is on the activity level now.
+ final float letterboxAspectRatioOverride = mWmService.getTaskLetterboxAspectRatio();
+ // Activity min/max aspect ratio restrictions will be respected by the activity-level
+ // letterboxing (size-compat mode). Therefore this override can control the maximum screen
+ // area that can be occupied by the app in the letterbox mode.
+ aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO
+ ? letterboxAspectRatioOverride : aspect;
+
+ // Store the current bounds to be able to revert to size compat mode values below if needed.
+ Rect mTmpFullBounds = new Rect(resolvedBounds);
+ if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+ final int height = (int) Math.rint(parentWidth / aspect);
+ final int top = parentBounds.centerY() - height / 2;
+ resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + height);
+ } else {
+ final int width = (int) Math.rint(parentHeight / aspect);
+ final int left = parentBounds.centerX() - width / 2;
+ resolvedBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
+ }
+
+ if (mCompatDisplayInsets != null) {
+ mCompatDisplayInsets.getBoundsByRotation(
+ mTmpBounds, newParentConfig.windowConfiguration.getRotation());
+ if (resolvedBounds.width() != mTmpBounds.width()
+ || resolvedBounds.height() != mTmpBounds.height()) {
+ // The app shouldn't be resized, we only do fixed orientation letterboxing if the
+ // compat bounds are also from the same fixed orientation letterbox. Otherwise,
+ // clear the fixed orientation bounds to show app in size compat mode.
+ resolvedBounds.set(mTmpFullBounds);
+ return;
+ }
+ }
+
+ // Calculate app bounds using fixed orientation bounds because they will be needed later
+ // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
+ task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
+ mIsLetterboxedForFixedOrientationAndAspectRatio = true;
+ }
+
+ /**
* Resolves the configuration of activity in fullscreen mode. If the bounds are restricted by
* aspect ratio, the position will be centered horizontally in parent's app bounds to balance
* the visual appearance. The policy of aspect ratio has higher priority than the requested
@@ -7037,6 +7119,18 @@
private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+
+ // When an activity needs to be letterboxed because of fixed orientation, use fixed
+ // orientation bounds (stored in resolved bounds) instead of parent bounds since the
+ // activity will be displayed within them even if it is in size compat mode. They should be
+ // saved here before resolved bounds are overridden below.
+ final Rect containerBounds = isLetterboxedForFixedOrientationAndAspectRatio()
+ ? new Rect(resolvedBounds)
+ : newParentConfiguration.windowConfiguration.getBounds();
+ final Rect containerAppBounds = isLetterboxedForFixedOrientationAndAspectRatio()
+ ? new Rect(getResolvedOverrideConfiguration().windowConfiguration.getAppBounds())
+ : newParentConfiguration.windowConfiguration.getAppBounds();
+
final int requestedOrientation = getRequestedConfigurationOrientation();
final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
final int orientation = orientationRequested
@@ -7095,7 +7189,7 @@
// Below figure is an example that puts an activity which was launched in a larger container
// into a smaller container.
// The outermost rectangle is the real display bounds.
- // "@" is the parent app bounds.
+ // "@" is the container app bounds (parent bounds or fixed orientation bouds)
// "#" is the {@code resolvedBounds} that applies to application.
// "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled.
// ------------------------------
@@ -7111,19 +7205,18 @@
// The application is still layouted in "#" since it was launched, and it will be visually
// scaled and positioned to "*".
+ 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.
- final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
- final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
- final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
final int contentW = resolvedAppBounds.width();
final int contentH = resolvedAppBounds.height();
- final int viewportW = parentAppBounds.width();
- final int viewportH = parentAppBounds.height();
+ final int viewportW = containerAppBounds.width();
+ final int viewportH = containerAppBounds.height();
// Only allow to scale down.
mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
? 1f : Math.min((float) viewportW / contentW, (float) viewportH / contentH);
- final int screenTopInset = parentAppBounds.top - parentBounds.top;
+ final int screenTopInset = containerAppBounds.top - containerBounds.top;
final boolean topNotAligned = screenTopInset != resolvedAppBounds.top - resolvedBounds.top;
if (mSizeCompatScale != 1f || topNotAligned) {
if (mSizeCompatBounds == null) {
@@ -7143,8 +7236,9 @@
final int offsetX = getHorizontalCenterOffset(
(int) viewportW, (int) (contentW * mSizeCompatScale));
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
- final int screenPosX = (fillContainer ? parentBounds.left : parentAppBounds.left) + offsetX;
- final int screenPosY = parentBounds.top;
+ final int screenPosX = (fillContainer
+ ? containerBounds.left : containerAppBounds.left) + offsetX;
+ final int screenPosY = containerBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
if (mSizeCompatBounds != null) {
mSizeCompatBounds.offset(screenPosX, screenPosY);
@@ -7154,6 +7248,52 @@
final int dy = screenPosY - resolvedBounds.top;
offsetBounds(resolvedConfig, dx, dy);
}
+
+ mInSizeCompatModeForBounds =
+ isInSizeCompatModeForBounds(resolvedAppBounds, containerAppBounds);
+ }
+
+ private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) {
+ final int appWidth = appBounds.width();
+ final int appHeight = appBounds.height();
+ final int containerAppWidth = containerBounds.width();
+ final int containerAppHeight = containerBounds.height();
+
+ if (containerAppWidth == appWidth && containerAppHeight == appHeight) {
+ // Matched the container bounds.
+ return false;
+ }
+ if (containerAppWidth > appWidth && containerAppHeight > appHeight) {
+ // Both sides are smaller than the container.
+ return true;
+ }
+ if (containerAppWidth < appWidth || containerAppHeight < appHeight) {
+ // One side is larger than the container.
+ return true;
+ }
+
+ // The rest of the condition is that only one side is smaller than the container, but it
+ // still needs to exclude the cases where the size is limited by the fixed aspect ratio.
+ if (info.maxAspectRatio > 0) {
+ final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
+ / Math.min(appWidth, appHeight);
+ if (aspectRatio >= info.maxAspectRatio) {
+ // The current size has reached the max aspect ratio.
+ return false;
+ }
+ }
+ if (info.minAspectRatio > 0) {
+ // The activity should have at least the min aspect ratio, so this checks if the
+ // container still has available space to provide larger aspect ratio.
+ final float containerAspectRatio =
+ (0.5f + Math.max(containerAppWidth, containerAppHeight))
+ / Math.min(containerAppWidth, containerAppHeight);
+ if (containerAspectRatio <= info.minAspectRatio) {
+ // The long side has reached the parent.
+ return false;
+ }
+ }
+ return true;
}
/** @return The horizontal offset of putting the content in the center of viewport. */
@@ -7305,7 +7445,8 @@
final Task rootTask = getRootTask();
final float minAspectRatio = info.minAspectRatio;
- if (task == null || rootTask == null || (inMultiWindowMode() && !shouldUseSizeCompatMode())
+ if (task == null || rootTask == null
+ || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
|| (maxAspectRatio == 0 && minAspectRatio == 0)
|| isInVrUiMode(getConfiguration())) {
// We don't enforce aspect ratio if the activity task is in multiwindow unless it
@@ -7443,8 +7584,6 @@
if (displayChanged) {
mLastReportedDisplayId = newDisplayId;
}
- // TODO(b/36505427): Is there a better place to do this?
- updateSizeCompatMode();
// Short circuit: if the two full configurations are equal (the common case), then there is
// nothing to do. We test the full configuration instead of the global and merged override
@@ -7723,11 +7862,6 @@
// Reset the existing override configuration so it can be updated according to the latest
// configuration.
clearSizeCompatMode();
- if (mVisibleRequested) {
- // Configuration will be ensured when becoming visible, so if it is already visible,
- // then the manual update is needed.
- updateSizeCompatMode();
- }
if (!attachedToProcess()) {
return;
@@ -8134,8 +8268,11 @@
private final int mHeight;
/** Whether the {@link Task} windowingMode represents a floating window*/
final boolean mIsFloating;
- /** Whether the {@link Task} is letterboxed when the unresizable activity is first shown. */
- final boolean mIsTaskLetterboxed;
+ /**
+ * Whether is letterboxed because of fixed orientation when the unresizable activity is
+ * first shown.
+ */
+ final boolean mIsInFixedOrientationLetterbox;
/**
* The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
* is used to compute the appBounds.
@@ -8149,7 +8286,8 @@
final Rect[] mStableInsets = new Rect[4];
/** Constructs the environment to simulate the bounds behavior of the given container. */
- CompatDisplayInsets(DisplayContent display, ActivityRecord container) {
+ CompatDisplayInsets(DisplayContent display, ActivityRecord container,
+ @Nullable Rect fixedOrientationBounds) {
mIsFloating = container.getWindowConfiguration().tasksAreFloating();
if (mIsFloating) {
final Rect containerBounds = container.getWindowConfiguration().getBounds();
@@ -8162,24 +8300,34 @@
mNonDecorInsets[rotation] = emptyRect;
mStableInsets[rotation] = emptyRect;
}
- mIsTaskLetterboxed = false;
+ mIsInFixedOrientationLetterbox = false;
return;
}
final Task task = container.getTask();
- mIsTaskLetterboxed = task != null && task.isTaskLetterboxed();
+
+ mIsInFixedOrientationLetterbox = fixedOrientationBounds != null;
// Store the bounds of the Task for the non-resizable activity to use in size compat
// mode so that the activity will not be resized regardless the windowing mode it is
// currently in.
- final WindowContainer filledContainer = task != null ? task : display;
- final Point dimensions = getRotationZeroDimensions(filledContainer);
+ // When an activity needs to be letterboxed because of fixed orientation, use fixed
+ // orientation bounds instead of task bounds since the activity will be displayed
+ // within these even if it is in size compat mode.
+ final Rect filledContainerBounds = mIsInFixedOrientationLetterbox
+ ? fixedOrientationBounds
+ : task != null ? task.getBounds() : display.getBounds();
+ final int filledContainerRotation = task != null
+ ? task.getConfiguration().windowConfiguration.getRotation()
+ : display.getConfiguration().windowConfiguration.getRotation();
+ final Point dimensions = getRotationZeroDimensions(
+ filledContainerBounds, filledContainerRotation);
mWidth = dimensions.x;
mHeight = dimensions.y;
// Bounds of the filled container if it doesn't fill the display.
final Rect unfilledContainerBounds =
- filledContainer.getBounds().equals(display.getBounds()) ? null : new Rect();
+ filledContainerBounds.equals(display.getBounds()) ? null : new Rect();
final DisplayPolicy policy = display.getDisplayPolicy();
for (int rotation = 0; rotation < 4; rotation++) {
mNonDecorInsets[rotation] = new Rect();
@@ -8199,9 +8347,9 @@
// The insets is based on the display, but the container may be smaller than the
// display, so update the insets to exclude parts that are not intersected with the
// container.
- unfilledContainerBounds.set(filledContainer.getBounds());
+ unfilledContainerBounds.set(filledContainerBounds);
display.rotateBounds(
- filledContainer.getConfiguration().windowConfiguration.getRotation(),
+ filledContainerRotation,
rotation,
unfilledContainerBounds);
updateInsetsForBounds(unfilledContainerBounds, dw, dh, mNonDecorInsets[rotation]);
@@ -8214,9 +8362,7 @@
* the display is rotated, we can calculate the bounds by rotating the dimensions.
* @see #getBoundsByRotation
*/
- private static Point getRotationZeroDimensions(WindowContainer container) {
- final Rect bounds = container.getBounds();
- final int rotation = container.getConfiguration().windowConfiguration.getRotation();
+ private static Point getRotationZeroDimensions(final Rect bounds, int rotation) {
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final int width = bounds.width();
final int height = bounds.height();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 60ca725..6ce9048 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1708,7 +1708,7 @@
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
- final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
+ final Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
if (topRootTask != null) {
startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants);
if (startResult != START_SUCCESS) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 94379b1..e858fe1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -348,13 +348,16 @@
public final class ActivityTokens {
private final @NonNull IBinder mActivityToken;
private final @NonNull IBinder mAssistToken;
+ private final @NonNull IBinder mShareableActivityToken;
private final @NonNull IApplicationThread mAppThread;
public ActivityTokens(@NonNull IBinder activityToken,
- @NonNull IBinder assistToken, @NonNull IApplicationThread appThread) {
+ @NonNull IBinder assistToken, @NonNull IApplicationThread appThread,
+ @NonNull IBinder shareableActivityToken) {
mActivityToken = activityToken;
mAssistToken = assistToken;
mAppThread = appThread;
+ mShareableActivityToken = shareableActivityToken;
}
/**
@@ -372,6 +375,13 @@
}
/**
+ * @return The sharable activity token..
+ */
+ public @NonNull IBinder getShareableActivityToken() {
+ return mShareableActivityToken;
+ }
+
+ /**
* @return The assist token.
*/
public @NonNull IApplicationThread getApplicationThread() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index af032c1..a874dee 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -58,7 +58,6 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
@@ -557,7 +556,6 @@
boolean mSupportsPictureInPicture;
boolean mSupportsMultiDisplay;
boolean mForceResizableActivities;
- boolean mSizeCompatFreeform;
boolean mSupportsNonResizableMultiWindow;
final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
@@ -788,8 +786,6 @@
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
- final boolean sizeCompatFreeform = Settings.Global.getInt(
- resolver, DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
final boolean supportsNonResizableMultiWindow = Settings.Global.getInt(
resolver, DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1) != 0;
@@ -805,7 +801,6 @@
synchronized (mGlobalLock) {
mForceResizableActivities = forceResizable;
- mSizeCompatFreeform = sizeCompatFreeform;
mSupportsNonResizableMultiWindow = supportsNonResizableMultiWindow;
final boolean multiWindowFormEnabled = freeformWindowManagement
|| supportsSplitScreenMultiWindow
@@ -5555,7 +5550,7 @@
return null;
}
return new ActivityTokens(activity.appToken, activity.assistToken,
- activity.app.getThread());
+ activity.app.getThread(), activity.shareableActivityToken);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bf2aae8..bb0f1f0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -825,7 +825,7 @@
r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
r.takeOptions(), dc.isNextTransitionForward(),
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
- r.createFixedRotationAdjustmentsIfNeeded()));
+ r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
new file mode 100644
index 0000000..13295e8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -0,0 +1,76 @@
+/*
+ * 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 static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
+
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.view.ICrossWindowBlurEnabledListener;
+
+final class BlurController {
+
+ private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
+ mBlurEnabledListeners = new RemoteCallbackList<>();
+ private final Object mLock = new Object();
+ boolean mBlurEnabled;
+
+ BlurController() {
+ mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+ }
+
+ boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
+ if (listener == null) return false;
+ mBlurEnabledListeners.register(listener);
+ synchronized (mLock) {
+ return mBlurEnabled;
+ }
+ }
+
+ void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
+ if (listener == null) return;
+ mBlurEnabledListeners.unregister(listener);
+ }
+
+ private void updateBlurEnabled() {
+ // TODO: add other factors disabling blurs
+ final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+ synchronized (mLock) {
+ if (mBlurEnabled == newEnabled) {
+ return;
+ }
+ mBlurEnabled = newEnabled;
+ notifyBlurEnabledChanged(newEnabled);
+ }
+ }
+
+ private void notifyBlurEnabledChanged(boolean enabled) {
+ int i = mBlurEnabledListeners.beginBroadcast();
+ while (i > 0) {
+ i--;
+ ICrossWindowBlurEnabledListener listener =
+ mBlurEnabledListeners.getBroadcastItem(i);
+ try {
+ listener.onCrossWindowBlurEnabledChanged(enabled);
+ } catch (RemoteException e) {
+ }
+ }
+ mBlurEnabledListeners.finishBroadcast();
+ }
+
+
+}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f64f04c..af9cdeb 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -69,6 +69,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
@@ -242,7 +243,7 @@
}
}
- private final SystemGesturesPointerEventListener mSystemGestures;
+ private SystemGesturesPointerEventListener mSystemGestures;
private volatile int mLidState = LID_ABSENT;
private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -384,7 +385,7 @@
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
- private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
+ private GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
@@ -448,119 +449,6 @@
final Looper looper = UiThread.getHandler().getLooper();
mHandler = new PolicyHandler(looper);
- mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
- new SystemGesturesPointerEventListener.Callbacks() {
- @Override
- public void onSwipeFromTop() {
- synchronized (mLock) {
- if (mStatusBar != null) {
- requestTransientBars(mStatusBar);
- }
- checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
- }
- }
-
- @Override
- public void onSwipeFromBottom() {
- synchronized (mLock) {
- if (mNavigationBar != null
- && mNavigationBarPosition == NAV_BAR_BOTTOM) {
- requestTransientBars(mNavigationBar);
- }
- checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
- }
- }
-
- @Override
- public void onSwipeFromRight() {
- final Region excludedRegion = Region.obtain();
- synchronized (mLock) {
- mDisplayContent.calculateSystemGestureExclusion(
- excludedRegion, null /* outUnrestricted */);
- final boolean excluded =
- mSystemGestures.currentGestureStartedInRegion(excludedRegion);
- if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
- || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
- requestTransientBars(mNavigationBar);
- }
- checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
- }
- excludedRegion.recycle();
- }
-
- @Override
- public void onSwipeFromLeft() {
- final Region excludedRegion = Region.obtain();
- synchronized (mLock) {
- mDisplayContent.calculateSystemGestureExclusion(
- excludedRegion, null /* outUnrestricted */);
- final boolean excluded =
- mSystemGestures.currentGestureStartedInRegion(excludedRegion);
- if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
- || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
- requestTransientBars(mNavigationBar);
- }
- checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
- }
- excludedRegion.recycle();
- }
-
- @Override
- public void onFling(int duration) {
- if (mService.mPowerManagerInternal != null) {
- mService.mPowerManagerInternal.setPowerBoost(
- Boost.INTERACTION, duration);
- }
- }
-
- @Override
- public void onDebug() {
- // no-op
- }
-
- private WindowOrientationListener getOrientationListener() {
- final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
- return rotation != null ? rotation.getOrientationListener() : null;
- }
-
- @Override
- public void onDown() {
- final WindowOrientationListener listener = getOrientationListener();
- if (listener != null) {
- listener.onTouchStart();
- }
- }
-
- @Override
- public void onUpOrCancel() {
- final WindowOrientationListener listener = getOrientationListener();
- if (listener != null) {
- listener.onTouchEnd();
- }
- }
-
- @Override
- public void onMouseHoverAtTop() {
- mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
- Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
- msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
- mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
- }
-
- @Override
- public void onMouseHoverAtBottom() {
- mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
- Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
- msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
- mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
- }
-
- @Override
- public void onMouseLeaveFromEdge() {
- mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
- }
- });
- displayContent.registerPointerEventListener(mSystemGestures);
mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
private Runnable mAppTransitionPending = () -> {
@@ -616,7 +504,7 @@
mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
mService.mVrModeEnabled);
- // TODO: Make it can take screenshot on external display
+ // TODO(b/180986447): Make it can take screenshot on external display
mScreenshotHelper = displayContent.isDefaultDisplay
? new ScreenshotHelper(mContext) : null;
@@ -640,16 +528,6 @@
mRefreshRatePolicy = new RefreshRatePolicy(mService,
mDisplayContent.getDisplayInfo(),
mService.mHighRefreshRateDenylist);
-
- mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
- mContext, () -> {
- synchronized (mLock) {
- onConfigurationChanged();
- mSystemGestures.onConfigurationChanged();
- mDisplayContent.updateSystemGestureExclusion();
- }
- });
- mHandler.post(mGestureNavigationSettingsObserver::register);
}
private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
@@ -668,12 +546,154 @@
}
void systemReady() {
- mSystemGestures.systemReady();
if (mService.mPointerLocationEnabled) {
setPointerLocationEnabled(true);
}
}
+ @NonNull
+ private GestureNavigationSettingsObserver getGestureNavigationSettingsObserver() {
+ if (mGestureNavigationSettingsObserver == null) {
+ mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
+ mContext, () -> {
+ synchronized (mLock) {
+ onConfigurationChanged();
+ getSystemGestures().onConfigurationChanged();
+ mDisplayContent.updateSystemGestureExclusion();
+ }
+ });
+ mHandler.post(mGestureNavigationSettingsObserver::register);
+ }
+ return mGestureNavigationSettingsObserver;
+ }
+
+ @NonNull
+ private SystemGesturesPointerEventListener getSystemGestures() {
+ if (mSystemGestures == null) {
+ final Context gestureContext = mUiContext.createWindowContext(
+ mDisplayContent.getDisplay(), TYPE_POINTER, null /* options */);
+ mSystemGestures = new SystemGesturesPointerEventListener(gestureContext, mHandler,
+ new SystemGesturesPointerEventListener.Callbacks() {
+ @Override
+ public void onSwipeFromTop() {
+ synchronized (mLock) {
+ if (mStatusBar != null) {
+ requestTransientBars(mStatusBar);
+ }
+ checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
+ }
+ }
+
+ @Override
+ public void onSwipeFromBottom() {
+ synchronized (mLock) {
+ if (mNavigationBar != null
+ && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ requestTransientBars(mNavigationBar);
+ }
+ checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
+ }
+ }
+
+ @Override
+ public void onSwipeFromRight() {
+ final Region excludedRegion = Region.obtain();
+ synchronized (mLock) {
+ mDisplayContent.calculateSystemGestureExclusion(
+ excludedRegion, null /* outUnrestricted */);
+ final boolean excluded = mSystemGestures
+ .currentGestureStartedInRegion(excludedRegion);
+ if (mNavigationBar != null
+ && (mNavigationBarPosition == NAV_BAR_RIGHT
+ || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+ requestTransientBars(mNavigationBar);
+ }
+ checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
+ }
+ excludedRegion.recycle();
+ }
+
+ @Override
+ public void onSwipeFromLeft() {
+ final Region excludedRegion = Region.obtain();
+ synchronized (mLock) {
+ mDisplayContent.calculateSystemGestureExclusion(
+ excludedRegion, null /* outUnrestricted */);
+ final boolean excluded = mSystemGestures
+ .currentGestureStartedInRegion(excludedRegion);
+ if (mNavigationBar != null
+ && (mNavigationBarPosition == NAV_BAR_LEFT
+ || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+ requestTransientBars(mNavigationBar);
+ }
+ checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
+ }
+ excludedRegion.recycle();
+ }
+
+ @Override
+ public void onFling(int duration) {
+ if (mService.mPowerManagerInternal != null) {
+ mService.mPowerManagerInternal.setPowerBoost(
+ Boost.INTERACTION, duration);
+ }
+ }
+
+ @Override
+ public void onDebug() {
+ // no-op
+ }
+
+ private WindowOrientationListener getOrientationListener() {
+ final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
+ return rotation != null ? rotation.getOrientationListener() : null;
+ }
+
+ @Override
+ public void onDown() {
+ final WindowOrientationListener listener = getOrientationListener();
+ if (listener != null) {
+ listener.onTouchStart();
+ }
+ }
+
+ @Override
+ public void onUpOrCancel() {
+ final WindowOrientationListener listener = getOrientationListener();
+ if (listener != null) {
+ listener.onTouchEnd();
+ }
+ }
+
+ @Override
+ public void onMouseHoverAtTop() {
+ mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+ Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+ msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
+ mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+ }
+
+ @Override
+ public void onMouseHoverAtBottom() {
+ mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+ Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+ msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
+ mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+ }
+
+ @Override
+ public void onMouseLeaveFromEdge() {
+ mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+ }
+ });
+ mDisplayContent.registerPointerEventListener(getSystemGestures());
+ if (mService.mSystemReady) {
+ mSystemGestures.systemReady();
+ }
+ }
+ return mSystemGestures;
+ }
+
private int getDisplayId() {
return mDisplayContent.getDisplayId();
}
@@ -1455,8 +1475,7 @@
}
void onDisplayInfoChanged(DisplayInfo info) {
- mSystemGestures.screenWidth = info.logicalWidth;
- mSystemGestures.screenHeight = info.logicalHeight;
+ getSystemGestures().onDisplayInfoChanged(info);
}
private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) {
@@ -1969,7 +1988,7 @@
public void onOverlayChangedLw() {
updateCurrentUserResources();
onConfigurationChanged();
- mSystemGestures.onConfigurationChanged();
+ getSystemGestures().onConfigurationChanged();
}
/**
@@ -2040,10 +2059,10 @@
}
mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
- mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
- mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
- mNavButtonForcedVisible =
- mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible();
+ final GestureNavigationSettingsObserver observer = getGestureNavigationSettingsObserver();
+ mLeftGestureInset = observer.getLeftSensitivity(res);
+ mRightGestureInset = observer.getRightSensitivity(res);
+ mNavButtonForcedVisible = observer.areNavigationButtonForcedVisible();
mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
mNavigationBarAlwaysShowOnSideGesture =
res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
@@ -2686,8 +2705,9 @@
boolean newImmersiveMode = isImmersiveMode(win);
if (oldImmersiveMode != newImmersiveMode) {
mLastImmersiveMode = newImmersiveMode;
- final String pkg = win.getOwningPackage();
- mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
+ // The immersive confirmation window should be attached to the immersive window root.
+ final int rootDisplayAreaId = win.getRootDisplayArea().mFeatureId;
+ mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId, newImmersiveMode,
mService.mPolicy.isUserSetupComplete(),
isNavBarEmpty(disableFlags));
}
@@ -3055,7 +3075,7 @@
}
void release() {
- mHandler.post(mGestureNavigationSettingsObserver::unregister);
+ mHandler.post(getGestureNavigationSettingsObserver()::unregister);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/FactoryErrorDialog.java b/services/core/java/com/android/server/wm/FactoryErrorDialog.java
index 88b5475..afdf1ee 100644
--- a/services/core/java/com/android/server/wm/FactoryErrorDialog.java
+++ b/services/core/java/com/android/server/wm/FactoryErrorDialog.java
@@ -41,6 +41,11 @@
public void onStop() {
}
+ @Override
+ protected void closeDialog() {
+ /* Do nothing */
+ }
+
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
throw new RuntimeException("Rebooting from failed factory test");
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 9286a46..567b6c2 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -19,9 +19,11 @@
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
@@ -32,10 +34,12 @@
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -43,6 +47,7 @@
import android.util.Slog;
import android.view.Display;
import android.view.Gravity;
+import android.view.IWindowManager;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -50,6 +55,7 @@
import android.view.WindowInsets;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -67,6 +73,8 @@
private static final boolean DEBUG = false;
private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution
private static final String CONFIRMED = "confirmed";
+ private static final int IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE =
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
private static boolean sConfirmed;
@@ -78,7 +86,15 @@
private ClingWindowView mClingWindow;
private long mPanicTime;
+ /** The last {@link WindowManager} that is used to add the confirmation window. */
+ @Nullable
private WindowManager mWindowManager;
+ /**
+ * The WindowContext that is registered with {@link #mWindowManager} with options to specify the
+ * {@link RootDisplayArea} to attach the confirmation window.
+ */
+ @Nullable
+ private Context mWindowContext;
// Local copy of vr mode enabled state, to avoid calling into VrManager with
// the lock held.
private boolean mVrModeEnabled;
@@ -132,7 +148,7 @@
}
}
- void immersiveModeChangedLw(String pkg, boolean isImmersiveMode,
+ void immersiveModeChangedLw(int rootDisplayAreaId, boolean isImmersiveMode,
boolean userSetupComplete, boolean navBarEmpty) {
mHandler.removeMessages(H.SHOW);
if (isImmersiveMode) {
@@ -143,7 +159,9 @@
&& !navBarEmpty
&& !UserManager.isDeviceInDemoMode(mContext)
&& (mLockTaskState != LOCK_TASK_MODE_LOCKED)) {
- mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
+ final Message msg = mHandler.obtainMessage(H.SHOW);
+ msg.arg1 = rootDisplayAreaId;
+ mHandler.sendMessageDelayed(msg, mShowDelayMs);
}
} else {
mHandler.sendEmptyMessage(H.HIDE);
@@ -175,7 +193,8 @@
private void handleHide() {
if (mClingWindow != null) {
if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
- getWindowManager().removeView(mClingWindow);
+ // We don't care which root display area the window manager is specifying for removal.
+ getWindowManager(FEATURE_UNDEFINED).removeView(mClingWindow);
mClingWindow = null;
}
}
@@ -184,7 +203,7 @@
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
+ IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
@@ -353,23 +372,57 @@
* DO HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD
* The reason why we add this method is to avoid the deadlock of WMG->WMS and WMS->WMG
* when ImmersiveModeConfirmation object is created.
+ *
+ * @return the WindowManager specifying with the {@code rootDisplayAreaId} to attach the
+ * confirmation window.
*/
- private WindowManager getWindowManager() {
- if (mWindowManager == null) {
- mWindowManager = (WindowManager)
- mContext.getSystemService(Context.WINDOW_SERVICE);
+ private WindowManager getWindowManager(int rootDisplayAreaId) {
+ if (mWindowManager == null || mWindowContext == null) {
+ // Create window context to specify the RootDisplayArea
+ final Bundle options = getOptionsForWindowContext(rootDisplayAreaId);
+ mWindowContext = mContext.createWindowContext(
+ IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE, options);
+ mWindowManager = mWindowContext.getSystemService(WindowManager.class);
+ return mWindowManager;
}
+
+ // Update the window context and window manager to specify the RootDisplayArea
+ final Bundle options = getOptionsForWindowContext(rootDisplayAreaId);
+ final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
+ try {
+ wms.registerWindowContextListener(mWindowContext.getWindowContextToken(),
+ IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE, mContext.getDisplayId(), options);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+
return mWindowManager;
}
- private void handleShow() {
+ /**
+ * Returns options that specify the {@link RootDisplayArea} to attach the confirmation window.
+ * {@code null} if the {@code rootDisplayAreaId} is {@link FEATURE_UNDEFINED}.
+ */
+ @Nullable
+ private Bundle getOptionsForWindowContext(int rootDisplayAreaId) {
+ // In case we don't care which root display area the window manager is specifying.
+ if (rootDisplayAreaId == FEATURE_UNDEFINED) {
+ return null;
+ }
+
+ final Bundle options = new Bundle();
+ options.putInt(DisplayAreaPolicyBuilder.KEY_ROOT_DISPLAY_AREA_ID, rootDisplayAreaId);
+ return options;
+ }
+
+ private void handleShow(int rootDisplayAreaId) {
if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation");
mClingWindow = new ClingWindowView(mContext, mConfirm);
// show the confirmation
WindowManager.LayoutParams lp = getClingWindowLayoutParams();
- getWindowManager().addView(mClingWindow, lp);
+ getWindowManager(rootDisplayAreaId).addView(mClingWindow, lp);
}
private final Runnable mConfirm = new Runnable() {
@@ -396,7 +449,7 @@
public void handleMessage(Message msg) {
switch(msg.what) {
case SHOW:
- handleShow();
+ handleShow(msg.arg1);
break;
case HIDE:
handleHide();
diff --git a/services/core/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
index 08de9b0..9bc7e93 100644
--- a/services/core/java/com/android/server/wm/PointerEventDispatcher.java
+++ b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
@@ -18,6 +18,7 @@
import static com.android.server.input.InputManagerService.ENABLE_PER_WINDOW_INPUT_ROTATION;
+import android.graphics.Point;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -35,6 +36,7 @@
private PointerEventListener[] mListenersArray = new PointerEventListener[0];
private final DisplayContent mDisplayContent;
+ private final Point mTmpSize = new Point();
public PointerEventDispatcher(InputChannel inputChannel, DisplayContent dc) {
super(inputChannel, UiThread.getHandler().getLooper());
@@ -48,12 +50,12 @@
&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
MotionEvent motionEvent = (MotionEvent) event;
if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
- int rotation = mDisplayContent.getRotation();
+ final int rotation = mDisplayContent.getRotation();
if (rotation != Surface.ROTATION_0) {
+ mDisplayContent.getDisplay().getRealSize(mTmpSize);
motionEvent = MotionEvent.obtain(motionEvent);
- motionEvent.transform(MotionEvent.createRotateMatrix(rotation,
- mDisplayContent.getDisplayMetrics().widthPixels,
- mDisplayContent.getDisplayMetrics().heightPixels));
+ motionEvent.transform(MotionEvent.createRotateMatrix(
+ rotation, mTmpSize.x, mTmpSize.y));
}
}
PointerEventListener[] listeners;
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index f3859b4..a98a478 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -126,11 +126,17 @@
Slog.w(TAG, "Cannot create GestureDetector, display removed:" + displayId);
return;
}
+ onDisplayInfoChanged(info);
mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) {
};
});
}
+ void onDisplayInfoChanged(DisplayInfo info) {
+ screenWidth = info.logicalWidth;
+ screenHeight = info.logicalHeight;
+ }
+
@Override
public void onPointerEvent(MotionEvent event) {
if (mGestureDetector != null && event.isTouchEvent()) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 29c7ff1..80173b5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -35,7 +35,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -148,7 +147,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.WindowManagerService.dipToPixel;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
@@ -597,10 +595,6 @@
@Nullable
private ActivityRecord mResumedActivity = null;
- /** Last activity that is used to compute the Task bounds. */
- @Nullable
- private ActivityRecord mLastTaskBoundsComputeActivity;
-
private boolean mForceShowForAllUsers;
/** When set, will force the task to report as invisible. */
@@ -841,6 +835,9 @@
// Tracking cookie for the creation of this task.
IBinder mLaunchCookie;
+ // The task will be removed when TaskOrganizer, which is managing the task, is destroyed.
+ boolean mRemoveWithTaskOrganizer;
+
private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -852,7 +849,8 @@
boolean supportsPictureInPicture, boolean _realActivitySuspended,
boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
- boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear) {
+ boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
+ boolean _removeWithTaskOrganizer) {
super(atmService.mWindowManager);
mAtmService = atmService;
@@ -911,6 +909,7 @@
mCreatedByOrganizer = _createdByOrganizer;
mLaunchCookie = _launchCookie;
mDeferTaskAppear = _deferTaskAppear;
+ mRemoveWithTaskOrganizer = _removeWithTaskOrganizer;
EventLogTags.writeWmTaskCreated(mTaskId, isRootTask() ? INVALID_TASK_ID : getRootTaskId());
}
@@ -1261,10 +1260,13 @@
* @param info The activity info which could be different from {@code r.info} if set.
*/
void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
- mCallingUid = r.launchedFromUid;
- mCallingPackage = r.launchedFromPackage;
- mCallingFeatureId = r.launchedFromFeatureId;
- setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
+ if (this.intent == null || !mNeverRelinquishIdentity) {
+ mCallingUid = r.launchedFromUid;
+ mCallingPackage = r.launchedFromPackage;
+ mCallingFeatureId = r.launchedFromFeatureId;
+ setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
+ return;
+ }
setLockTaskAuth(r);
}
@@ -1272,13 +1274,7 @@
private void setIntent(Intent _intent, ActivityInfo info) {
if (!isLeafTask()) return;
- if (intent == null) {
- mNeverRelinquishIdentity =
- (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
- } else if (mNeverRelinquishIdentity) {
- return;
- }
-
+ mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
affinity = info.taskAffinity;
if (intent == null) {
// If this task already has an intent associated with it, don't set the root
@@ -1496,11 +1492,6 @@
}
void cleanUpActivityReferences(ActivityRecord r) {
- // mLastTaskBoundsComputeActivity is set at leaf Task
- if (mLastTaskBoundsComputeActivity == r) {
- mLastTaskBoundsComputeActivity = null;
- }
-
// mPausingActivity is set at leaf task
if (mPausingActivity != null && mPausingActivity == r) {
mPausingActivity = null;
@@ -2847,8 +2838,6 @@
windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
&& candidateWindowingMode != WINDOWING_MODE_PINNED
- && (candidateWindowingMode != WINDOWING_MODE_FREEFORM
- || !mTaskSupervisor.mService.mSizeCompatFreeform)
&& !mTaskSupervisor.mService.mSupportsNonResizableMultiWindow) {
getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
WINDOWING_MODE_FULLSCREEN);
@@ -2863,7 +2852,6 @@
private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
Rect previousBounds) {
- mLastTaskBoundsComputeActivity = getTopNonFinishingActivity(false /* includeOverlays */);
int windowingMode =
getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
@@ -2877,7 +2865,8 @@
getResolvedOverrideConfiguration().windowConfiguration.getBounds();
if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
- computeFullscreenBounds(outOverrideBounds, newParentConfig);
+ // Use empty bounds to indicate "fill parent".
+ outOverrideBounds.setEmpty();
// The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
// the parent or display is smaller than the size, the content may be cropped.
return;
@@ -2888,21 +2877,6 @@
computeFreeformBounds(outOverrideBounds, newParentConfig);
return;
}
-
- if (isSplitScreenWindowingMode(windowingMode)
- || windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
- // This is to compute whether the task should be letterboxed to handle non-resizable app
- // in multi window. There is no split screen only logic.
- computeLetterboxBounds(outOverrideBounds, newParentConfig);
- }
- }
-
- /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}. */
- @VisibleForTesting
- void computeFullscreenBounds(@NonNull Rect outBounds, @NonNull Configuration newParentConfig) {
- // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
- outBounds.setEmpty();
- computeLetterboxBounds(outBounds, newParentConfig);
}
/** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
@@ -2934,94 +2908,6 @@
}
}
- /**
- * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation
- * change and the requested orientation is different from the parent.
- */
- private void computeLetterboxBounds(@NonNull Rect outBounds,
- @NonNull Configuration newParentConfig) {
- if (handlesOrientationChangeFromDescendant()) {
- // No need to letterbox at task level. Display will handle fixed-orientation requests.
- return;
- }
-
- final int parentOrientation = newParentConfig.orientation;
- // Use the top activity as the reference of orientation. Don't include overlays because
- // it is usually not the actual content or just temporarily shown.
- // E.g. ForcedResizableInfoActivity.
- final ActivityRecord refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
-
- // If the task or the reference activity requires a different orientation (either by
- // override or activityInfo), make it fit the available bounds by scaling down its bounds.
- final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
- final int forcedOrientation =
- (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
- ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
- if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
- return;
- }
-
- final ActivityRecord.CompatDisplayInsets compatDisplayInsets =
- refActivity == null ? null : refActivity.getCompatDisplayInsets();
- if (compatDisplayInsets != null && !compatDisplayInsets.mIsTaskLetterboxed) {
- // App prefers to keep its original size.
- // If the size compat is from previous task letterboxing, we may want to have task
- // letterbox again, otherwise it will show the size compat restart button even if the
- // restart bounds will be the same.
- return;
- }
-
- final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
- final int parentWidth = parentBounds.width();
- final int parentHeight = parentBounds.height();
- float aspect = Math.max(parentWidth, parentHeight)
- / (float) Math.min(parentWidth, parentHeight);
-
- // Adjust the Task letterbox bounds to fit the app request aspect ratio in order to use the
- // extra available space.
- if (refActivity != null) {
- final float maxAspectRatio = refActivity.info.maxAspectRatio;
- final float minAspectRatio = refActivity.info.minAspectRatio;
- if (aspect > maxAspectRatio && maxAspectRatio != 0) {
- aspect = maxAspectRatio;
- } else if (aspect < minAspectRatio) {
- aspect = minAspectRatio;
- }
- }
-
- // Override from config_letterboxAspectRatio or via ADB with set-letterbox-aspect-ratio.
- final float letterboxAspectRatioOverride = mWmService.getTaskLetterboxAspectRatio();
- // Activity min/max aspect ratio restrictions will be respected by the activity-level
- // letterboxing (size-compat mode). Therefore this override can control the maximum screen
- // area that can be occupied by the app in the letterbox mode.
- aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO
- ? letterboxAspectRatioOverride : aspect;
-
- // Store the current bounds to be able to revert to size compat mode values below if needed.
- mTmpFullBounds.set(outBounds);
- if (forcedOrientation == ORIENTATION_LANDSCAPE) {
- final int height = (int) Math.rint(parentWidth / aspect);
- final int top = parentBounds.centerY() - height / 2;
- outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
- } else {
- final int width = (int) Math.rint(parentHeight / aspect);
- final int left = parentBounds.centerX() - width / 2;
- outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
- }
-
- if (compatDisplayInsets != null) {
- compatDisplayInsets.getBoundsByRotation(
- mTmpBounds, newParentConfig.windowConfiguration.getRotation());
- if (outBounds.width() != mTmpBounds.width()
- || outBounds.height() != mTmpBounds.height()) {
- // The app shouldn't be resized, we only do task letterboxing if the compat bounds
- // is also from the same task letterbox. Otherwise, clear the task bounds to show
- // app in size compat mode.
- outBounds.set(mTmpFullBounds);
- }
- }
- }
-
Rect updateOverrideConfigurationFromLaunchBounds() {
// If the task is controlled by another organized task, do not set override
// configurations and let its parent (organized task) to control it;
@@ -3036,11 +2922,6 @@
return bounds;
}
- @Nullable
- ActivityRecord getLastTaskBoundsComputeActivity() {
- return mLastTaskBoundsComputeActivity;
- }
-
/** Updates the task's bounds and override configuration to match what is expected for the
* input root task. */
void updateOverrideConfigurationForRootTask(Task inRootTask) {
@@ -3939,12 +3820,6 @@
|| activityType == ACTIVITY_TYPE_ASSISTANT;
}
- boolean isTaskLetterboxed() {
- // No letterbox for multi window root task
- return !matchParentBounds()
- && (getWindowingMode() == WINDOWING_MODE_FULLSCREEN || !isRootTask());
- }
-
@Override
boolean fillsParent() {
// From the perspective of policy, we still want to report that this task fills parent
@@ -7970,6 +7845,7 @@
private IBinder mLaunchCookie;
private boolean mOnTop;
private boolean mHasBeenVisible;
+ private boolean mRemoveWithTaskOrganizer;
Builder(ActivityTaskManagerService atm) {
mAtmService = atm;
@@ -8265,6 +8141,9 @@
mCallingPackage = mActivityInfo.packageName;
mResizeMode = mActivityInfo.resizeMode;
mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
+ if (mActivityOptions != null) {
+ mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer();
+ }
final Task task = buildInner();
task.mHasBeenVisible = mHasBeenVisible;
@@ -8303,7 +8182,7 @@
mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
- mLaunchCookie, mDeferTaskAppear);
+ mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 106db0b..f3b69e3 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -234,19 +234,28 @@
}
}
- // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the policy
- // that legacy (pre-D) apps and those apps that can't handle multiple screen density well
- // are forced to be maximized. The rest of this step is to define the default policy when
- // there is no initial bounds or a fully resolved current params from callers.
+ // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the
+ // policies related to unresizable apps here. If an app is unresizable and the freeform
+ // size-compat mode is enabled, it can be launched in freeform depending on other properties
+ // such as orientation. Otherwise, the app is forcefully launched in maximized. The rest of
+ // this step is to define the default policy when there is no initial bounds or a fully
+ // resolved current params from callers.
if (display.inFreeformWindowingMode()) {
if (launchMode == WINDOWING_MODE_PINNED) {
if (DEBUG) appendLog("picture-in-picture");
- } else if (!mSupervisor.mService.mSizeCompatFreeform && !root.isResizeable()) {
- // We're launching an activity in size-compat mode and they aren't allowed in
- // freeform, so force it to be maximized.
- launchMode = WINDOWING_MODE_FULLSCREEN;
- outParams.mBounds.setEmpty();
- if (DEBUG) appendLog("forced-maximize");
+ } else if (!root.isResizeable()) {
+ if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea)) {
+ launchMode = WINDOWING_MODE_FREEFORM;
+ if (outParams.mBounds.isEmpty()) {
+ getTaskBounds(root, display, layout, launchMode, hasInitialBounds,
+ outParams.mBounds);
+ }
+ if (DEBUG) appendLog("unresizable-freeform");
+ } else {
+ launchMode = WINDOWING_MODE_FULLSCREEN;
+ outParams.mBounds.setEmpty();
+ if (DEBUG) appendLog("unresizable-forced-maximize");
+ }
}
} else {
if (DEBUG) appendLog("non-freeform-display");
@@ -322,7 +331,6 @@
}
getTaskBounds(root, display, layout, resolvedMode, hasInitialBounds, outParams.mBounds);
}
-
return RESULT_CONTINUE;
}
@@ -562,6 +570,27 @@
outBounds.offset(xOffset, yOffset);
}
+ private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity,
+ TaskDisplayArea displayArea) {
+ if (!mSupervisor.mService.mSupportsNonResizableMultiWindow || activity.isResizeable()) {
+ return false;
+ }
+ final DisplayContent display = displayArea.getDisplayContent();
+ if (display == null) {
+ return false;
+ }
+
+ final int displayOrientation = orientationFromBounds(displayArea.getBounds());
+ final int activityOrientation = resolveOrientation(activity, display,
+ displayArea.getBounds());
+ if (displayArea.getWindowingMode() == WINDOWING_MODE_FREEFORM
+ && displayOrientation != activityOrientation) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Resolves activity requested orientation to 4 categories:
* 1) {@link ActivityInfo#SCREEN_ORIENTATION_LOCKED} indicating app wants to lock down
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 1531e56..fc6db61 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -285,18 +285,20 @@
return false;
}
- private boolean removeTask(Task t) {
+ private boolean removeTask(Task t, boolean removeFromSystem) {
mOrganizedTasks.remove(t);
mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
-
- if (t.mTaskAppearedSent) {
+ boolean taskAppearedSent = t.mTaskAppearedSent;
+ if (taskAppearedSent) {
if (t.getSurfaceControl() != null) {
t.migrateToNewSurfaceControl();
}
t.mTaskAppearedSent = false;
- return true;
}
- return false;
+ if (removeFromSystem) {
+ mService.removeTask(t.mTaskId);
+ }
+ return taskAppearedSent;
}
void dispose() {
@@ -311,7 +313,7 @@
if (mOrganizedTasks.contains(t)) {
// updateTaskOrganizerState should remove the task from the list, but still
// check it again to avoid while-loop isn't terminate.
- if (removeTask(t)) {
+ if (removeTask(t, t.mRemoveWithTaskOrganizer)) {
TaskOrganizerController.this.onTaskVanishedInternal(
mOrganizer.mTaskOrganizer, t);
}
@@ -527,7 +529,7 @@
void onTaskVanished(ITaskOrganizer organizer, Task task) {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
- if (state != null && state.removeTask(task)) {
+ if (state != null && state.removeTask(task, false /* removeFromSystem */)) {
onTaskVanishedInternal(organizer, task);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 71d2b2f..cec0321 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -39,7 +39,6 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
@@ -224,6 +223,7 @@
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.ICrossWindowBlurEnabledListener;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
@@ -253,6 +253,7 @@
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.RemoteAnimationAdapter;
+import android.view.ScrollCaptureResponse;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -756,6 +757,8 @@
final TaskSnapshotController mTaskSnapshotController;
+ final BlurController mBlurController = new BlurController();
+
boolean mIsTouchDevice;
boolean mIsFakeTouchDevice;
@@ -802,8 +805,6 @@
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT);
private final Uri mForceResizableUri = Settings.Global.getUriFor(
DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
- private final Uri mSizeCompatFreeformUri = Settings.Global.getUriFor(
- DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
private final Uri mSupportsNonResizableMultiWindowUri = Settings.Global.getUriFor(
DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW);
private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor(
@@ -830,8 +831,6 @@
UserHandle.USER_ALL);
resolver.registerContentObserver(mFreeformWindowUri, false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(mSizeCompatFreeformUri, false, this,
- UserHandle.USER_ALL);
resolver.registerContentObserver(mSupportsNonResizableMultiWindowUri, false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
@@ -871,11 +870,6 @@
return;
}
- if (mSizeCompatFreeformUri.equals(uri)) {
- updateSizeCompatFreeform();
- return;
- }
-
if (mSupportsNonResizableMultiWindowUri.equals(uri)) {
updateSupportsNonResizableMultiWindow();
return;
@@ -973,14 +967,6 @@
mAtmService.mForceResizableActivities = forceResizable;
}
- void updateSizeCompatFreeform() {
- ContentResolver resolver = mContext.getContentResolver();
- final boolean sizeCompatFreeform = Settings.Global.getInt(resolver,
- DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
-
- mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
- }
-
void updateSupportsNonResizableMultiWindow() {
ContentResolver resolver = mContext.getContentResolver();
final boolean supportsNonResizableMultiWindow = Settings.Global.getInt(resolver,
@@ -2393,15 +2379,9 @@
}
}
- // We may be deferring layout passes at the moment, but since the client is interested
- // in the new out values right now we need to force a layout.
- mWindowPlacerLocked.performSurfacePlacement(true /* force */);
-
+ // Create surfaceControl before surface placement otherwise layout will be skipped
+ // (because WS.isGoneForLayout() is true when there is no surface.
if (shouldRelayout) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
-
- result = win.relayoutVisibleWindow(result);
-
try {
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
} catch (Exception e) {
@@ -2413,6 +2393,17 @@
Binder.restoreCallingIdentity(origId);
return 0;
}
+ }
+
+ // We may be deferring layout passes at the moment, but since the client is interested
+ // in the new out values right now we need to force a layout.
+ mWindowPlacerLocked.performSurfacePlacement(true /* force */);
+
+ if (shouldRelayout) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
+
+ result = win.relayoutVisibleWindow(result);
+
if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
focusMayChange = true;
}
@@ -5684,6 +5675,18 @@
return mWindowTracing.isEnabled();
}
+ @Override
+ public boolean registerCrossWindowBlurEnabledListener(
+ ICrossWindowBlurEnabledListener listener) {
+ return mBlurController.registerCrossWindowBlurEnabledListener(listener);
+ }
+
+ @Override
+ public void unregisterCrossWindowBlurEnabledListener(
+ ICrossWindowBlurEnabledListener listener) {
+ mBlurController.unregisterCrossWindowBlurEnabledListener(listener);
+ }
+
// -------------------------------------------------------------
// Internals
// -------------------------------------------------------------
@@ -6423,6 +6426,7 @@
}
});
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
+ pw.print(" mBlurEnabled="); pw.println(mBlurController.mBlurEnabled);
pw.print(" mLastDisplayFreezeDuration=");
TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
if ( mLastFinishedFreezeSource != null) {
@@ -7154,12 +7158,14 @@
}
final long token = Binder.clearCallingIdentity();
try {
+ ScrollCaptureResponse.Builder responseBuilder = new ScrollCaptureResponse.Builder();
synchronized (mGlobalLock) {
DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc == null) {
ProtoLog.e(WM_ERROR,
"Invalid displayId for requestScrollCapture: %d", displayId);
- callbacks.onUnavailable();
+ responseBuilder.setDescription(String.format("bad displayId: %d", displayId));
+ callbacks.onScrollCaptureResponse(responseBuilder.build());
return;
}
WindowState topWindow = null;
@@ -7168,17 +7174,20 @@
}
WindowState targetWindow = dc.findScrollCaptureTargetWindow(topWindow, taskId);
if (targetWindow == null) {
- callbacks.onUnavailable();
+ responseBuilder.setDescription("findScrollCaptureTargetWindow returned null");
+ callbacks.onScrollCaptureResponse(responseBuilder.build());
return;
}
- // Forward to the window for handling.
try {
+ // Forward to the window for handling, which will respond using the callback.
targetWindow.mClient.requestScrollCapture(callbacks);
} catch (RemoteException e) {
ProtoLog.w(WM_ERROR,
"requestScrollCapture: caught exception dispatching to window."
+ "token=%s", targetWindow.mClient.asBinder());
- callbacks.onUnavailable();
+ responseBuilder.setWindowTitle(targetWindow.getName());
+ responseBuilder.setDescription(String.format("caught exception: %s", e));
+ callbacks.onScrollCaptureResponse(responseBuilder.build());
}
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9ae5beb..2a9e08e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3827,13 +3827,21 @@
/** @return true when the window should be letterboxed. */
boolean isLetterboxedAppWindow() {
// Fullscreen mode but doesn't fill display area.
- return (!inMultiWindowMode() && !matchesDisplayAreaBounds())
- // Activity in size compat.
- || (mActivityRecord != null && mActivityRecord.inSizeCompatMode())
- // Task letterboxed.
- || (getTask() != null && getTask().isTaskLetterboxed())
- // Letterboxed for display cutout.
- || isLetterboxedForDisplayCutout();
+ if (!inMultiWindowMode() && !matchesDisplayAreaBounds()) {
+ return true;
+ }
+ if (mActivityRecord != null) {
+ // Activity in size compat.
+ if (mActivityRecord.inSizeCompatMode()) {
+ return true;
+ }
+ // Letterbox for fixed orientation.
+ if (mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio()) {
+ return true;
+ }
+ }
+ // Letterboxed for display cutout.
+ return isLetterboxedForDisplayCutout();
}
/** Returns {@code true} if the window is letterboxed for the display cutout. */
@@ -5265,22 +5273,24 @@
if (!mAnimatingExit && mAppDied) {
mIsDimming = true;
getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
- } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || (mAttrs.flags & FLAG_BLUR_BEHIND) != 0)
+ } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
&& isVisibleNow() && !mHidden) {
// Only show the Dimmer when the following is satisfied:
- // 1. The window has the flag FLAG_DIM_BEHIND or background blur is requested
+ // 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
// 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
// 3. The WS is considered visible according to the isVisible() method
// 4. The WS is not hidden.
mIsDimming = true;
final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
- final int blurRadius =
- (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 ? mAttrs.blurBehindRadius : 0;
- getDimmer().dimBelow(
- getSyncTransaction(), this, mAttrs.dimAmount, mAttrs.blurBehindRadius);
+ final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
+ getDimmer().dimBelow(getSyncTransaction(), this, mAttrs.dimAmount, blurRadius);
}
}
+ private boolean shouldDrawBlurBehind() {
+ return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mWmService.mBlurController.mBlurEnabled;
+ }
+
/**
* Notifies SF about the priority of the window, if it changed. SF then uses this information
* to decide which window's desired rendering rate should have a priority when deciding about
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index f054e7c..8c6d084 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -232,21 +232,6 @@
compactProcessOrFallback(pid, compactionFlags);
}
-static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal(
- JNIEnv *env, jobject clazz, jboolean enable) {
- bool success = true;
-
- if (enable) {
- success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
- } else {
- success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
- }
-
- if (!success) {
- jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
- }
-}
-
static void com_android_server_am_CachedAppOptimizer_freezeBinder(
JNIEnv *env, jobject clazz, jint pid, jboolean freeze) {
@@ -280,15 +265,19 @@
static jstring com_android_server_am_CachedAppOptimizer_getFreezerCheckPath(JNIEnv* env,
jobject clazz) {
- return env->NewStringUTF(CGROUP_FREEZE_PATH);
+ std::string path;
+
+ if (!getAttributePathForTask("FreezerState", getpid(), &path)) {
+ path = "";
+ }
+
+ return env->NewStringUTF(path.c_str());
}
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
{"compactProcess", "(II)V", (void*)com_android_server_am_CachedAppOptimizer_compactProcess},
- {"enableFreezerInternal", "(Z)V",
- (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
{"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder},
{"getBinderFreezeInfo", "(I)I",
(void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 524892b..28e9acf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -715,6 +715,9 @@
@Nullable
private DevicePolicySafetyChecker mSafetyChecker;
+ @GuardedBy("getLockObject()")
+ private final ArrayList<Object> mPendingUserCreatedCallbackTokens = new ArrayList<>();
+
public static final class Lifecycle extends SystemService {
private BaseIDevicePolicyManager mService;
@@ -753,21 +756,25 @@
@Override
public void onUserStarting(@NonNull TargetUser user) {
+ if (user.isPreCreated()) return;
mService.handleStartUser(user.getUserIdentifier());
}
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
+ if (user.isPreCreated()) return;
mService.handleUnlockUser(user.getUserIdentifier());
}
@Override
public void onUserStopping(@NonNull TargetUser user) {
+ if (user.isPreCreated()) return;
mService.handleStopUser(user.getUserIdentifier());
}
@Override
public void onUserUnlocked(@NonNull TargetUser user) {
+ if (user.isPreCreated()) return;
mService.handleOnUserUnlocked(user.getUserIdentifier());
}
}
@@ -965,8 +972,8 @@
private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
@Override
- public void onUserCreated(UserInfo user) {
- mHandler.post(() -> handleNewUserCreated(user));
+ public void onUserCreated(UserInfo user, Object token) {
+ mHandler.post(() -> handleNewUserCreated(user, token));
}
}
@@ -3151,11 +3158,6 @@
if (!mHasFeature) {
return;
}
- setActiveAdmin(adminReceiver, refreshing, userHandle, null);
- }
-
- private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
- Bundle onEnableData) {
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
final CallerIdentity caller = getCallerIdentity();
@@ -3198,7 +3200,7 @@
}
saveSettingsLocked(userHandle);
sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
- onEnableData, null);
+ /* adminExtras= */ null, /* result= */ null);
});
}
}
@@ -9187,13 +9189,24 @@
pw.println();
mStatLogger.dump(pw);
pw.println();
-
pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
pw.println();
+
+ if (mPendingUserCreatedCallbackTokens.isEmpty()) {
+ pw.println("no pending user created callback tokens");
+ } else {
+ int size = mPendingUserCreatedCallbackTokens.size();
+ pw.printf("%d pending user created callback token%s\n", size,
+ (size == 1 ? "" : "s"));
+ }
+ pw.println();
+
mPolicyCache.dump(pw);
pw.println();
mStateCache.dump(pw);
+ pw.println();
}
+ dumpResources(pw);
}
}
@@ -9208,6 +9221,32 @@
pw.decreaseIndent();
}
+ private void dumpResources(IndentingPrintWriter pw) {
+ mOverlayPackagesProvider.dump(pw);
+ pw.println();
+
+ pw.println("Other overlayable app resources");
+ pw.increaseIndent();
+ dumpResources(pw, mContext, "cross_profile_apps", R.array.cross_profile_apps);
+ dumpResources(pw, mContext, "vendor_cross_profile_apps", R.array.vendor_cross_profile_apps);
+ pw.decreaseIndent();
+ pw.println();
+ }
+
+ static void dumpResources(IndentingPrintWriter pw, Context context, String resName, int resId) {
+ String[] apps = context.getResources().getStringArray(resId);
+ if (apps == null || apps.length == 0) {
+ pw.printf("%s: empty\n", resName);
+ return;
+ }
+ pw.printf("%s: %d app%s\n", resName, apps.length, apps.length == 1 ? "" : "s");
+ pw.increaseIndent();
+ for (int i = 0; i < apps.length; i++) {
+ pw.printf("%d: %s\n", i, apps[i]);
+ }
+ pw.decreaseIndent();
+ }
+
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
@@ -9946,8 +9985,8 @@
clearInitBundle = sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
initBundle == null ? null : new Bundle(initBundle),
- null /* result receiver */,
- true /* send in foreground */);
+ /* result= */ null ,
+ /* inForeground= */ true);
}
if (clearInitBundle) {
// If there's no admin or we've successfully called the admin, clear the init bundle
@@ -10020,9 +10059,13 @@
UserHandle.myUserId(), ACTION_PROVISION_MANAGED_USER).toArray(
new String[0]);
}
+
+ Object token = new Object();
+ Slog.d(LOG_TAG, "Adding new pending token: " + token);
+ mPendingUserCreatedCallbackTokens.add(token);
try {
UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
- userType, userInfoFlags, disallowedPackages);
+ userType, userInfoFlags, disallowedPackages, token);
if (userInfo != null) {
user = userInfo.getUserHandle();
}
@@ -10032,7 +10075,8 @@
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
- }
+ } // synchronized
+
if (user == null) {
if (targetSdkVersion >= Build.VERSION_CODES.P) {
throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN,
@@ -10054,14 +10098,8 @@
final long id = mInjector.binderClearCallingIdentity();
try {
- if (!mInjector.userManagerIsHeadlessSystemUserMode()) {
- manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
- /* showDisclaimer= */ true);
- } else if (VERBOSE_LOG) {
- Slog.v(LOG_TAG, "createAndManageUser(): skipping manageUserUnchecked() on user "
- + userHandle + " on headless system user as it will be called by "
- + "handleNewUserCreated()");
- }
+ manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
+ /* showDisclaimer= */ true);
if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -10083,7 +10121,15 @@
}
private void manageUserUnchecked(ComponentName admin, ComponentName profileOwner,
- @UserIdInt int userId, PersistableBundle adminExtras, boolean showDisclaimer) {
+ @UserIdInt int userId, @Nullable PersistableBundle adminExtras,
+ boolean showDisclaimer) {
+ synchronized (getLockObject()) {
+ if (VERBOSE_LOG) {
+ Slog.v(LOG_TAG, "manageUserUnchecked(): admin=" + admin + ", po=" + profileOwner
+ + ", userId=" + userId + ", hasAdminExtras=" + (adminExtras != null)
+ + ", showDisclaimer=" + showDisclaimer);
+ }
+ }
final String adminPkg = admin.getPackageName();
try {
// Install the profile owner if not present.
@@ -10113,23 +10159,37 @@
? DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED
: DevicePolicyData.NEW_USER_DISCLAIMER_NOT_NEEDED;
saveSettingsLocked(userId);
+
}
}
- private void handleNewUserCreated(UserInfo user) {
- if (VERBOSE_LOG) Slog.v(LOG_TAG, "handleNewUserCreated(): " + user.toFullString());
-
- if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return;
+ private void handleNewUserCreated(UserInfo user, @Nullable Object token) {
+ if (VERBOSE_LOG) {
+ Slog.v(LOG_TAG, "handleNewUserCreated(): user=" + user.toFullString()
+ + ", token=" + token);
+ }
final int userId = user.id;
+ if (token != null) {
+ synchronized (getLockObject()) {
+ if (mPendingUserCreatedCallbackTokens.contains(token)) {
+ // Ignore because it was triggered by createAndManageUser()
+ Slog.d(LOG_TAG, "handleNewUserCreated(): ignoring for user " + userId
+ + " due to token" + token);
+ mPendingUserCreatedCallbackTokens.remove(token);
+ return;
+ }
+ }
+ }
+
+ if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return;
if (mInjector.userManagerIsHeadlessSystemUserMode()) {
ComponentName admin = mOwners.getDeviceOwnerComponent();
Slog.i(LOG_TAG, "Automatically setting profile owner (" + admin + ") on new user "
+ userId);
manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
- /* managedUser= */ userId, /* adminExtras= */ null,
- /* showDisclaimer= */ true);
+ /* managedUser= */ userId, /* adminExtras= */ null, /* showDisclaimer= */ true);
} else {
Log.i(LOG_TAG, "User " + userId + " added on DO mode; setting ShowNewUserDisclaimer");
setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED);
@@ -10250,11 +10310,12 @@
final long id = mInjector.binderClearCallingIdentity();
try {
if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) {
- Log.w(LOG_TAG, "Cannot start more users in background");
+ Log.w(LOG_TAG, "Cannot start user " + userId + ", too many users in background");
return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
}
if (mInjector.getIActivityManager().startUserInBackground(userId)) {
+ Log.i(LOG_TAG, "Started used " + userId + " in background");
return UserManager.USER_OPERATION_SUCCESS;
} else {
return UserManager.USER_OPERATION_ERROR_UNKNOWN;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
index 261a83c..280f12f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
@@ -21,6 +21,7 @@
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.devicepolicy.DevicePolicyManagerService.dumpResources;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -32,6 +33,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.view.inputmethod.InputMethodInfo;
import com.android.internal.R;
@@ -224,4 +226,39 @@
}
return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
}
+
+ void dump(IndentingPrintWriter pw) {
+ pw.println("OverlayPackagesProvider");
+ pw.increaseIndent();
+
+ dumpResources(pw, mContext, "required_apps_managed_device",
+ R.array.required_apps_managed_device);
+ dumpResources(pw, mContext, "required_apps_managed_user",
+ R.array.required_apps_managed_user);
+ dumpResources(pw, mContext, "required_apps_managed_profile",
+ R.array.required_apps_managed_profile);
+
+ dumpResources(pw, mContext, "disallowed_apps_managed_device",
+ R.array.disallowed_apps_managed_device);
+ dumpResources(pw, mContext, "disallowed_apps_managed_user",
+ R.array.disallowed_apps_managed_user);
+ dumpResources(pw, mContext, "disallowed_apps_managed_device",
+ R.array.disallowed_apps_managed_device);
+
+ dumpResources(pw, mContext, "vendor_required_apps_managed_device",
+ R.array.vendor_required_apps_managed_device);
+ dumpResources(pw, mContext, "vendor_required_apps_managed_user",
+ R.array.vendor_required_apps_managed_user);
+ dumpResources(pw, mContext, "vendor_required_apps_managed_profile",
+ R.array.vendor_required_apps_managed_profile);
+
+ dumpResources(pw, mContext, "vendor_disallowed_apps_managed_user",
+ R.array.vendor_disallowed_apps_managed_user);
+ dumpResources(pw, mContext, "vendor_disallowed_apps_managed_device",
+ R.array.vendor_disallowed_apps_managed_device);
+ dumpResources(pw, mContext, "vendor_disallowed_apps_managed_profile",
+ R.array.vendor_disallowed_apps_managed_profile);
+
+ pw.decreaseIndent();
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6bbd320..a3d3353 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -162,6 +162,7 @@
import com.android.server.pm.UserManagerService;
import com.android.server.pm.dex.SystemServerDexLoadReporter;
import com.android.server.pm.verify.domain.DomainVerificationService;
+import com.android.server.policy.AppOpsPolicy;
import com.android.server.policy.PermissionPolicyService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.policy.role.RoleServicePlatformHelperImpl;
@@ -2656,6 +2657,14 @@
}
t.traceEnd();
+ t.traceBegin("RegisterAppOpsPolicy");
+ try {
+ mActivityManagerService.setAppOpsPolicy(new AppOpsPolicy());
+ } catch (Throwable e) {
+ reportWtf("registering app ops policy", e);
+ }
+ t.traceEnd();
+
// No dependency on Webview preparation in system server. But this should
// be completed before allowing 3rd party
final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
diff --git a/services/net/Android.bp b/services/net/Android.bp
index c68004a..b01e425 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -52,6 +52,7 @@
libs: [
"unsupportedappusage",
"framework-wifi-util-lib",
+ "framework-connectivity"
],
static_libs: [
// All the classes in netd_aidl_interface must be jarjar so they do not conflict with the
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 e99b071..0fa9a1d 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
@@ -52,8 +52,10 @@
val collector = mockCollector()
assertThat(collector.collectAllWebDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com")
- assertThat(collector.collectAutoVerifyDomains(pkg))
+ assertThat(collector.collectValidAutoVerifyDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com", "example4.com")
+ assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+ .containsExactly("invalid1", "invalid2", "invalid3", "invalid4")
}
@Test
@@ -62,7 +64,8 @@
val collector = mockCollector()
assertThat(collector.collectAllWebDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com")
- assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
}
@Test
@@ -71,8 +74,10 @@
val collector = mockCollector(linkedApps = setOf(TEST_PKG_NAME))
assertThat(collector.collectAllWebDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com")
- assertThat(collector.collectAutoVerifyDomains(pkg))
+ assertThat(collector.collectValidAutoVerifyDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com", "example4.com")
+ assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+ .containsExactly("invalid1", "invalid2", "invalid3", "invalid4")
}
@Test
@@ -92,6 +97,7 @@
addDataScheme("https")
addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example1.com", null)
+ addDataAuthority("invalid1", null)
}
)
},
@@ -111,6 +117,7 @@
addDataScheme("nonWebScheme")
addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example2.com", null)
+ addDataAuthority("invalid2", null)
}
)
},
@@ -122,7 +129,8 @@
val collector = mockCollector()
assertThat(collector.collectAllWebDomains(pkg))
.containsExactly("example1.com", "example2.com")
- assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
}
@Test
@@ -132,8 +140,10 @@
assertThat(collector.collectAllWebDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com")
- assertThat(collector.collectAutoVerifyDomains(pkg))
+ assertThat(collector.collectValidAutoVerifyDomains(pkg))
.containsExactly("example1.com", "example3.com")
+ assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+ .containsExactly("invalid1", "invalid3")
}
@Test
@@ -143,7 +153,8 @@
assertThat(collector.collectAllWebDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com")
- assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
}
@Test
@@ -153,7 +164,8 @@
assertThat(collector.collectAllWebDomains(pkg))
.containsExactly("example1.com", "example2.com", "example3.com")
- assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+ assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
}
private fun mockCollector(linkedApps: Set<String> = emptySet()): DomainVerificationCollector {
@@ -178,6 +190,7 @@
<data android:scheme="https"/>
<data android:path="/sub"/>
<data android:host="example1.com"/>
+ <data android:host="invalid1"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
@@ -186,6 +199,7 @@
<data android:scheme="http"/>
<data android:path="/sub2"/>
<data android:host="example2.com"/>
+ <data android:host="invalid2."/>
</intent-filter>
<intent-filter android:autoVerify="$autoVerify">
<action android:name="android.intent.action.VIEW"/>
@@ -194,6 +208,7 @@
<data android:scheme="https"/>
<data android:path="/sub3"/>
<data android:host="example3.com"/>
+ <data android:host=".invalid3"/>
</intent-filter>
<intent-filter android:autoVerify="$autoVerify">
<action android:name="android.intent.action.VIEW"/>
@@ -201,6 +216,7 @@
<data android:scheme="https"/>
<data android:path="/sub4"/>
<data android:host="example4.com"/>
+ <data android:host="invalid4"/>
</intent-filter>
<intent-filter android:autoVerify="$autoVerify">
<action android:name="android.intent.action.VIEW"/>
@@ -208,6 +224,7 @@
<data android:scheme="https"/>
<data android:path="/sub5"/>
<data android:host="example5.com"/>
+ <data android:host="invalid5"/>
</intent-filter>
<intent-filter android:autoVerify="$autoVerify">
<category android:name="android.intent.category.BROWSABLE"/>
@@ -215,11 +232,12 @@
<data android:scheme="https"/>
<data android:path="/sub5"/>
<data android:host="example5.com"/>
+ <data android:host="invalid5"/>
</intent-filter>
</xml>
""".trimIndent()
- return mockThrowOnUnmocked<AndroidPackage> {
+ return mockThrowOnUnmocked {
whenever(packageName) { TEST_PKG_NAME }
whenever(targetSdkVersion) {
if (useV2) Build.VERSION_CODES.S else Build.VERSION_CODES.R
@@ -238,6 +256,7 @@
addDataScheme("https")
addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example1.com", null)
+ addDataAuthority("invalid1", null)
}
)
addIntent(
@@ -248,6 +267,7 @@
addDataScheme("http")
addDataPath("/sub2", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example2.com", null)
+ addDataAuthority("invalid2", null)
}
)
},
@@ -261,6 +281,7 @@
addDataScheme("https")
addDataPath("/sub3", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example3.com", null)
+ addDataAuthority("invalid3", null)
}
)
},
@@ -273,6 +294,7 @@
addDataScheme("https")
addDataPath("/sub4", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example4.com", null)
+ addDataAuthority("invalid4", null)
}
)
addIntent(
@@ -283,6 +305,7 @@
addDataScheme("https")
addDataPath("/sub5", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example5.com", null)
+ addDataAuthority("invalid5", null)
}
)
addIntent(
@@ -293,6 +316,7 @@
addDataScheme("https")
addDataPath("/sub6", PatternMatcher.PATTERN_LITERAL)
addDataAuthority("example6.com", null)
+ addDataAuthority("invalid6", null)
}
)
},
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
index deb3147..9447f39 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
@@ -16,8 +16,9 @@
package com.android.server.pm.test.verify.domain
-import android.content.pm.verify.domain.DomainVerificationRequest
+import android.content.pm.verify.domain.DomainSet
import android.content.pm.verify.domain.DomainVerificationInfo
+import android.content.pm.verify.domain.DomainVerificationRequest
import android.content.pm.verify.domain.DomainVerificationUserSelection
import android.os.Parcel
import android.os.Parcelable
@@ -27,6 +28,7 @@
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.util.UUID
+import kotlin.random.Random
@RunWith(Parameterized::class)
class DomainVerificationCoreApiTest {
@@ -40,18 +42,25 @@
assertThat(value).containsExactlyEntriesIn(other)
}
+ private val massiveSet by lazy {
+ val fragmentOf21 = ".com.example.test.app"
+ val list = mutableListOf("prefix$fragmentOf21")
+ var totalSize = 0
+ // Slightly overshoot a size of 1MB
+ while (totalSize < (1024 * 512)) {
+ val nextValue = "${list.last()}$fragmentOf21"
+ totalSize += nextValue.length
+ list += nextValue
+ }
+ list.toSet()
+ }
+
@JvmStatic
- @Parameterized.Parameters
+ @Parameterized.Parameters(name = "{0}")
fun parameters() = arrayOf(
Parameter(
- initial = {
- DomainVerificationRequest(
- setOf(
- "com.test.pkg.one",
- "com.test.pkg.two"
- )
- )
- },
+ testName = "DomainVerificationRequest",
+ initial = { DomainVerificationRequest(massiveSet) },
unparcel = { DomainVerificationRequest.CREATOR.createFromParcel(it) },
assertion = { first, second ->
assertAll<DomainVerificationRequest, Set<String>>(first, second,
@@ -61,15 +70,12 @@
}
),
Parameter(
+ testName = "DomainVerificationInfo",
initial = {
DomainVerificationInfo(
UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
"com.test.pkg",
- mapOf(
- "example.com" to 0,
- "example.org" to 1,
- "example.new" to 1000
- )
+ massiveSet.withIndex().associate { it.value to it.index }
)
},
unparcel = { DomainVerificationInfo.CREATOR.createFromParcel(it) },
@@ -86,17 +92,15 @@
}
),
Parameter(
+ testName = "DomainVerificationUserSelection",
initial = {
DomainVerificationUserSelection(
UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
"com.test.pkg",
UserHandle.of(10),
true,
- mapOf(
- "example.com" to true,
- "example.org" to false,
- "example.new" to true
- )
+ massiveSet.withIndex()
+ .associate { it.value to (it.index % 3) }
)
},
unparcel = { DomainVerificationUserSelection.CREATOR.createFromParcel(it) },
@@ -114,21 +118,35 @@
first, second, { it.isLinkHandlingAllowed },
{ it.component4() }, IS_EQUAL_TO
)
- assertAll<DomainVerificationUserSelection, Map<String, Boolean>>(
- first, second, { it.hostToUserSelectionMap },
+ assertAll<DomainVerificationUserSelection, Map<String, Int>>(
+ first, second, { it.hostToStateMap },
{ it.component5() }, IS_MAP_EQUAL_TO
)
}
+ ),
+ Parameter(
+ testName = "DomainSet",
+ initial = { DomainSet(massiveSet) },
+ unparcel = { DomainSet.CREATOR.createFromParcel(it) },
+ assertion = { first, second ->
+ assertAll<DomainSet, Set<String>>(
+ first, second,
+ { it.domains }, assertion = IS_EQUAL_TO
+ )
+ }
)
)
class Parameter<T : Parcelable>(
+ val testName: String,
val initial: () -> T,
val unparcel: (Parcel) -> T,
private val assertion: (first: T, second: T) -> Unit
) {
@Suppress("UNCHECKED_CAST")
fun assert(first: Any, second: Any) = assertion(first as T, second as T)
+
+ override fun toString() = testName
}
private fun <T> assertAll(vararg values: T, block: (value: T, other: T) -> Unit) {
@@ -141,11 +159,17 @@
first: T,
second: T,
fieldValue: (T) -> V,
- componentValue: (T) -> V,
+ componentValue: ((T) -> V)? = null,
assertion: (value: V, other: V) -> Unit
) {
- val values = arrayOf<Any>(fieldValue(first), fieldValue(second),
- componentValue(first), componentValue(second))
+ val values = mutableListOf<Any>(fieldValue(first), fieldValue(second))
+ .apply {
+ componentValue?.let {
+ add(it(first))
+ add(it(second))
+ }
+ }
+ .toTypedArray()
values.indices.drop(1).forEach {
@Suppress("UNCHECKED_CAST")
assertion(values[0] as V, values[it] as V)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 2d23fb4..89394837 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -244,6 +244,14 @@
service(Type.LEGACY_QUERENT, "getLegacyUserState") {
getLegacyState(it.targetPackageName, it.userId)
},
+ service(Type.OWNER_QUERENT, "getOwnersForDomain") {
+ // Re-use package name, since the result itself isn't relevant
+ getOwnersForDomain(it.targetPackageName)
+ },
+ service(Type.OWNER_QUERENT_USER, "getOwnersForDomainUserId") {
+ // Re-use package name, since the result itself isn't relevant
+ getOwnersForDomain(it.targetPackageName, it.userId)
+ },
)
}
@@ -327,6 +335,7 @@
domainSetId
)
) {
+ whenever(getName()) { packageName }
whenever(getPkg()) { mockPkg(packageName) }
whenever(this.domainSetId) { domainSetId }
whenever(userState) {
@@ -357,6 +366,8 @@
Type.SELECTOR_USER -> approvedUserSelector(verifyCrossUser = true)
Type.LEGACY_QUERENT -> legacyQuerent()
Type.LEGACY_SELECTOR -> legacyUserSelector()
+ Type.OWNER_QUERENT -> ownerQuerent(verifyCrossUser = false)
+ Type.OWNER_QUERENT_USER -> ownerQuerent(verifyCrossUser = true)
}.run { /*exhaust*/ }
}
@@ -628,6 +639,80 @@
runTestCases(callingUserId, notCallingUserId, throws = false)
}
+ private fun ownerQuerent(verifyCrossUser: Boolean) {
+ val allowQueryAll = AtomicBoolean(false)
+ val allowUserSelection = AtomicBoolean(false)
+ val allowInteractAcrossUsers = AtomicBoolean(false)
+ val context: Context = mockThrowOnUnmocked {
+ initPermission(
+ allowQueryAll,
+ android.Manifest.permission.QUERY_ALL_PACKAGES
+ )
+ initPermission(
+ allowUserSelection,
+ android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
+ )
+ initPermission(
+ allowInteractAcrossUsers,
+ android.Manifest.permission.INTERACT_ACROSS_USERS
+ )
+ }
+ val target = params.construct(context)
+
+ fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) {
+ // Owner querent makes no distinction by UID
+ val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID
+ if (throws) {
+ allUids.forEach {
+ assertFails {
+ runMethod(target, it, visible = true, callingUserId, targetUserId)
+ }
+ }
+ } else {
+ allUids.forEach {
+ runMethod(target, it, visible = true, callingUserId, targetUserId)
+ }
+ }
+ }
+
+ val callingUserId = 0
+ val notCallingUserId = 1
+
+ runTestCases(callingUserId, callingUserId, throws = true)
+ if (verifyCrossUser) {
+ runTestCases(callingUserId, notCallingUserId, throws = true)
+ }
+
+ allowQueryAll.set(true)
+
+ runTestCases(callingUserId, callingUserId, throws = true)
+ if (verifyCrossUser) {
+ runTestCases(callingUserId, notCallingUserId, throws = true)
+ }
+
+ allowUserSelection.set(true)
+
+ runTestCases(callingUserId, callingUserId, throws = false)
+ if (verifyCrossUser) {
+ runTestCases(callingUserId, notCallingUserId, throws = true)
+ }
+
+ allowQueryAll.set(false)
+
+ runTestCases(callingUserId, callingUserId, throws = true)
+ if (verifyCrossUser) {
+ runTestCases(callingUserId, notCallingUserId, throws = true)
+ }
+
+ allowQueryAll.set(true)
+ allowInteractAcrossUsers.set(true)
+
+ runTestCases(callingUserId, callingUserId, throws = false)
+ if (verifyCrossUser) {
+ runTestCases(callingUserId, notCallingUserId, throws = false)
+ }
+ }
+
private fun Context.initPermission(boolean: AtomicBoolean, permission: String) {
whenever(enforcePermission(eq(permission), anyInt(), anyInt(), anyString())) {
if (!boolean.get()) {
@@ -694,6 +779,12 @@
LEGACY_QUERENT,
// Holding the legacy preferred apps permission
- LEGACY_SELECTOR
+ LEGACY_SELECTOR,
+
+ // Holding user setting permission, but not targeting a package
+ OWNER_QUERENT,
+
+ // Holding user setting permission, but not targeting a package, but targeting cross user
+ OWNER_QUERENT_USER,
}
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
new file mode 100644
index 0000000..48056a2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
@@ -0,0 +1,174 @@
+/*
+ * 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.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.parsing.component.ParsedActivity
+import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.verify.domain.DomainVerificationManager
+import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.os.Build
+import android.os.PatternMatcher
+import android.os.Process
+import android.util.ArraySet
+import androidx.test.InstrumentationRegistry
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.verify.domain.DomainVerificationService
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.anyString
+import java.util.UUID
+
+class DomainVerificationManagerUserSelectionOverrideTest {
+
+ companion object {
+ private const val PKG_ONE = "com.test.one"
+ private const val PKG_TWO = "com.test.two"
+ private val UUID_ONE = UUID.fromString("1b041c96-8d37-4932-a858-561bfac5947c")
+ private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c")
+
+ private val DOMAIN_ONE =
+ DomainVerificationManagerUserSelectionOverrideTest::class.java.packageName
+
+ private const val STATE_NONE = DomainVerificationUserSelection.DOMAIN_STATE_NONE
+ private const val STATE_SELECTED = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED
+ private const val STATE_VERIFIED = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED
+ }
+
+ private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE)
+ private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO)
+
+ fun makeManager(): DomainVerificationManager =
+ DomainVerificationService(mockThrowOnUnmocked {
+ // Assume the test has every permission necessary
+ whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString()))
+ whenever(checkPermission(anyString(), anyInt(), anyInt())) {
+ PackageManager.PERMISSION_GRANTED
+ }
+ }, mockThrowOnUnmocked {
+ whenever(linkedApps) { ArraySet<String>() }
+ }, mockThrowOnUnmocked {
+ whenever(isChangeEnabled(anyLong(), any())) { true }
+ }).apply {
+ setConnection(mockThrowOnUnmocked {
+ whenever(filterAppAccess(anyString(), anyInt(), anyInt())) { false }
+ whenever(scheduleWriteSettings())
+
+ // Need to provide an internal UID so some permission checks are ignored
+ whenever(callingUid) { Process.ROOT_UID }
+ whenever(callingUserId) { 0 }
+ whenever(getPackageSettingLocked(PKG_ONE)) { pkg1 }
+ whenever(getPackageSettingLocked(PKG_TWO)) { pkg2 }
+ whenever(getPackageLocked(PKG_ONE)) { pkg1.getPkg() }
+ whenever(getPackageLocked(PKG_TWO)) { pkg2.getPkg() }
+ })
+ addPackage(pkg1)
+ addPackage(pkg2)
+
+ // Starting state for all tests is to have domain 1 enabled for the first package
+ setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true)
+
+ assertThat(stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
+ }
+
+ fun mockPkgSetting(pkgName: String, domainSetId: UUID) = mockThrowOnUnmocked<PackageSetting> {
+ val pkg = mockThrowOnUnmocked<AndroidPackage> {
+ whenever(packageName) { pkgName }
+ whenever(targetSdkVersion) { Build.VERSION_CODES.S }
+
+ val activityList = listOf(
+ ParsedActivity().apply {
+ addIntent(
+ ParsedIntentInfo().apply {
+ autoVerify = true
+ addAction(Intent.ACTION_VIEW)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("http")
+ addDataScheme("https")
+ addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
+ addDataAuthority(DOMAIN_ONE, null)
+ }
+ )
+ addIntent(
+ ParsedIntentInfo().apply {
+ autoVerify = true
+ addAction(Intent.ACTION_VIEW)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("http")
+ addDataPath("/sub2", PatternMatcher.PATTERN_LITERAL)
+ addDataAuthority("example2.com", null)
+ }
+ )
+ },
+ )
+
+ whenever(activities) { activityList }
+ }
+
+ whenever(getPkg()) { pkg }
+ whenever(getName()) { pkgName }
+ whenever(this.domainSetId) { domainSetId }
+ whenever(getInstantApp(anyInt())) { false }
+ whenever(firstInstallTime) { 0L }
+ }
+
+ @Test
+ fun anotherPackageTakeoverSuccess() {
+ val manager = makeManager()
+
+ // Attempt override by package 2
+ manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+
+ // 1 loses approval
+ assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
+
+ // 2 gains approval
+ assertThat(manager.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
+
+ // 2 is the only owner
+ assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+ .containsExactly(PKG_TWO)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun anotherPackageTakeoverFailure() {
+ val manager = makeManager()
+
+ // Verify 1 to give it a higher approval level
+ manager.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
+ DomainVerificationManager.STATE_SUCCESS)
+ assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
+ assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+ .containsExactly(PKG_ONE)
+
+ // Attempt override by package 2
+ manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+ }
+
+ private fun DomainVerificationManager.stateFor(pkgName: String, host: String) =
+ getDomainVerificationUserSelection(pkgName)!!.hostToStateMap[host]
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
index a76d8ce..439048c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
@@ -34,7 +34,7 @@
operator fun DomainVerificationUserSelection.component2() = packageName
operator fun DomainVerificationUserSelection.component3() = user
operator fun DomainVerificationUserSelection.component4() = isLinkHandlingAllowed
-operator fun DomainVerificationUserSelection.component5() = hostToUserSelectionMap
+operator fun DomainVerificationUserSelection.component5() = hostToStateMap
operator fun DomainVerificationPersistence.ReadResult.component1() = active
operator fun DomainVerificationPersistence.ReadResult.component2() = restored
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
index db541f6..91e5bec 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
@@ -122,7 +122,7 @@
whenever(setDomainVerificationStatusInternal(anyInt(), any(), any(), anyInt()))
}
collector = mockThrowOnUnmocked {
- whenever(collectAutoVerifyDomains(any())) {
+ whenever(collectValidAutoVerifyDomains(any())) {
when (val pkgName = (arguments[0] as AndroidPackage).packageName) {
TEST_PKG_NAME_TARGET_ONE -> ArraySet(setOf("example1.com", "example2.com"))
TEST_PKG_NAME_TARGET_TWO -> ArraySet(setOf("example3.com", "example4.com"))
@@ -477,7 +477,7 @@
whenever(
addPowerSaveTempWhitelistApp(
anyInt(), anyString(), anyLong(), anyInt(),
- anyBoolean(), anyString()
+ anyBoolean(), anyInt(), anyString()
)
)
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 48518f46..010eacf 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -237,6 +237,7 @@
TEST_UUID
)
) {
+ whenever(getName()) { TEST_PKG }
whenever(getPkg()) { mockPkg() }
whenever(domainSetId) { TEST_UUID }
whenever(userState) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 775276b..f7f5928 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -19,6 +19,7 @@
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_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -611,6 +612,7 @@
private static NetworkCapabilities createCapabilities() {
return new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_VALIDATED);
}
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 bf95f4c..29db740 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
@@ -1326,6 +1326,46 @@
}
@Test
+ public void testGetMaxJobExecutionTimeLocked_Regular_Active() {
+ JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked_Regular_Active", 0);
+ setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 10 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 10 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, 2 * HOUR_IN_MILLIS);
+ setDischarging();
+ setStandbyBucket(ACTIVE_INDEX, job);
+ setProcessState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+
+ // ACTIVE apps (where allowed time = window size) should be capped at max execution limit.
+ synchronized (mQuotaController.mLock) {
+ assertEquals(2 * HOUR_IN_MILLIS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+ }
+
+ // Make sure sessions are factored in properly.
+ mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+ createTimingSession(sElapsedRealtimeClock.millis() - (6 * HOUR_IN_MILLIS),
+ 30 * MINUTE_IN_MILLIS, 1), false);
+ synchronized (mQuotaController.mLock) {
+ assertEquals(90 * MINUTE_IN_MILLIS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+ }
+
+ mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+ createTimingSession(sElapsedRealtimeClock.millis() - (5 * HOUR_IN_MILLIS),
+ 30 * MINUTE_IN_MILLIS, 1), false);
+ mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+ createTimingSession(sElapsedRealtimeClock.millis() - (4 * HOUR_IN_MILLIS),
+ 30 * MINUTE_IN_MILLIS, 1), false);
+ mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+ createTimingSession(sElapsedRealtimeClock.millis() - (3 * HOUR_IN_MILLIS),
+ 25 * MINUTE_IN_MILLIS, 1), false);
+ synchronized (mQuotaController.mLock) {
+ assertEquals(5 * MINUTE_IN_MILLIS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+ }
+ }
+
+ @Test
public void testGetMaxJobExecutionTimeLocked_EJ() {
final long timeUsedMs = 3 * MINUTE_IN_MILLIS;
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
index 69fe140..e0c8b09 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
@@ -500,7 +500,7 @@
}
@Override
- protected boolean isAntennaInfoListeningSupported() {
+ protected boolean isAntennaInfoSupported() {
return mIsAntennaInfoListeningSupported;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 68d6557..1b58e92 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -352,7 +352,8 @@
@Test
public void testGetLastLocation_ClearOnMockRemoval() {
- MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, PROVIDER_IDENTITY);
+ MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, PROVIDER_IDENTITY,
+ Collections.emptySet());
mockProvider.setAllowed(true);
mManager.setMockProvider(mockProvider);
@@ -1048,7 +1049,7 @@
private final ArrayList<Runnable> mFlushCallbacks = new ArrayList<>();
TestProvider(ProviderProperties properties, CallerIdentity identity) {
- super(DIRECT_EXECUTOR, identity, properties);
+ super(DIRECT_EXECUTOR, identity, properties, Collections.emptySet());
}
public void setProviderAllowed(boolean allowed) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
index 07170da..cf5db2e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
@@ -43,6 +43,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collections;
+
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -71,7 +73,8 @@
.setPowerUsage(POWER_USAGE_LOW)
.setAccuracy(ACCURACY_FINE)
.build(),
- CallerIdentity.forTest(0, 1, "testpackage", "test"));
+ CallerIdentity.forTest(0, 1, "testpackage", "test"),
+ Collections.emptySet());
mProvider = new MockableLocationProvider(lock);
mProvider.getController().setListener(mListener);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
index 775bdd5..2bc1268 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
@@ -23,6 +23,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Collections;
public class FakeProvider extends AbstractLocationProvider {
@@ -40,7 +41,7 @@
private final FakeProviderInterface mFakeInterface;
public FakeProvider(FakeProviderInterface fakeInterface) {
- super(Runnable::run, null, null);
+ super(Runnable::run, null, null, Collections.emptySet());
mFakeInterface = fakeInterface;
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index bea4ae3..68f5479 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -181,9 +181,12 @@
":FrameworksServicesTests_install_split_feature_a",
":FrameworksServicesTests_install_uses_sdk_0",
":FrameworksServicesTests_install_uses_sdk_q0",
- ":FrameworksServicesTests_install_uses_sdk_r",
+ ":FrameworksServicesTests_install_uses_sdk_q0_r0",
+ ":FrameworksServicesTests_install_uses_sdk_r_none",
":FrameworksServicesTests_install_uses_sdk_r0",
":FrameworksServicesTests_install_uses_sdk_r5",
+ ":FrameworksServicesTests_install_uses_sdk_r0_s0",
+ ":FrameworksServicesTests_install_uses_sdk_r0_s5",
],
out: ["FrameworkServicesTests_apks_as_resources.res.zip"],
tools: ["soong_zip"],
diff --git a/services/tests/servicestests/apks/install_uses_sdk/Android.bp b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
index feb152c..a51293d 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/Android.bp
+++ b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
@@ -8,41 +8,49 @@
}
android_test_helper_app {
+ name: "FrameworksServicesTests_install_uses_sdk_q0",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ manifest: "AndroidManifest-q0.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_install_uses_sdk_q0_r0",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ manifest: "AndroidManifest-q0-r0.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_install_uses_sdk_r_none",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ manifest: "AndroidManifest-r-none.xml",
+}
+
+android_test_helper_app {
name: "FrameworksServicesTests_install_uses_sdk_r0",
defaults: ["FrameworksServicesTests_apks_defaults"],
manifest: "AndroidManifest-r0.xml",
-
- srcs: ["**/*.java"],
}
android_test_helper_app {
name: "FrameworksServicesTests_install_uses_sdk_r5",
defaults: ["FrameworksServicesTests_apks_defaults"],
manifest: "AndroidManifest-r5.xml",
-
- srcs: ["**/*.java"],
}
android_test_helper_app {
- name: "FrameworksServicesTests_install_uses_sdk_q0",
+ name: "FrameworksServicesTests_install_uses_sdk_r0_s0",
defaults: ["FrameworksServicesTests_apks_defaults"],
- manifest: "AndroidManifest-q0.xml",
-
- srcs: ["**/*.java"],
+ manifest: "AndroidManifest-r0-s0.xml",
}
android_test_helper_app {
- name: "FrameworksServicesTests_install_uses_sdk_r",
+ name: "FrameworksServicesTests_install_uses_sdk_r0_s5",
defaults: ["FrameworksServicesTests_apks_defaults"],
- manifest: "AndroidManifest-r.xml",
-
- srcs: ["**/*.java"],
+ manifest: "AndroidManifest-r0-s5.xml",
}
android_test_helper_app {
name: "FrameworksServicesTests_install_uses_sdk_0",
defaults: ["FrameworksServicesTests_apks_defaults"],
manifest: "AndroidManifest-0.xml",
-
- srcs: ["**/*.java"],
}
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
index 215384b..90b13d4 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
@@ -18,7 +18,7 @@
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
<!-- This is invalid, because there is no sdk version specified -->
- <extension-sdk android:minExtensionVersion="5" />
+ <extension-sdk android:minExtensionVersion="0" />
</uses-sdk>
<application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
similarity index 80%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
index 5d22577..2a32276 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
@@ -17,8 +17,9 @@
package="com.android.frameworks.servicestests.install_uses_sdk">
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
- <!-- This is invalid, because there is no minimum extension version specified -->
- <extension-sdk android:sdkVersion="10000" />
+ <!-- This fails because 29 doesn't have an extension sdk -->
+ <extension-sdk android:sdkVersion="29" android:minExtensionVersion="0" />
+ <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
</uses-sdk>
<application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
similarity index 94%
rename from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
index 5d22577..c79c61c 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
@@ -18,7 +18,7 @@
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
<!-- This is invalid, because there is no minimum extension version specified -->
- <extension-sdk android:sdkVersion="10000" />
+ <extension-sdk android:sdkVersion="30" />
</uses-sdk>
<application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
similarity index 84%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
index 5d22577..af30915 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
@@ -17,8 +17,8 @@
package="com.android.frameworks.servicestests.install_uses_sdk">
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
- <!-- This is invalid, because there is no minimum extension version specified -->
- <extension-sdk android:sdkVersion="10000" />
+ <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
+ <extension-sdk android:sdkVersion="31" android:minExtensionVersion="0" />
</uses-sdk>
<application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
similarity index 80%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
index 5d22577..bafe4c4 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
@@ -17,8 +17,9 @@
package="com.android.frameworks.servicestests.install_uses_sdk">
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
- <!-- This is invalid, because there is no minimum extension version specified -->
- <extension-sdk android:sdkVersion="10000" />
+ <!-- This fails because 31 is not version 5 -->
+ <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
+ <extension-sdk android:sdkVersion="31" android:minExtensionVersion="5" />
</uses-sdk>
<application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
index c1244f2..2920b86 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
@@ -17,7 +17,7 @@
package="com.android.frameworks.servicestests.install_uses_sdk">
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
- <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="0" />
+ <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
</uses-sdk>
<application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
index 3410938..7723d05 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
@@ -18,7 +18,7 @@
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
<!-- This will fail to install, because minExtensionVersion is not met -->
- <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="5" />
+ <extension-sdk android:sdkVersion="30" android:minExtensionVersion="5" />
</uses-sdk>
<application>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
index 895fb17..5dbf837 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
@@ -69,7 +69,7 @@
mContext = InstrumentationRegistry.getContext();
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mObserver = new MagnificationGesturesObserver(mCallback, new SimpleSwipe(mContext),
- new TwoFingersDown(mContext));
+ new TwoFingersDownOrSwipe(mContext));
}
@Test
@@ -77,9 +77,7 @@
final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
DEFAULT_X , DEFAULT_Y);
- mInstrumentation.runOnMainSync(() -> {
- mObserver.onMotionEvent(moveEvent, moveEvent, 0);
- });
+ mObserver.onMotionEvent(moveEvent, moveEvent, 0);
verify(mCallback).onGestureCancelled(eq(0L),
mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(moveEvent)));
@@ -92,9 +90,7 @@
final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
DEFAULT_X , DEFAULT_Y);
- mInstrumentation.runOnMainSync(() -> {
- mObserver.onMotionEvent(downEvent, downEvent, 0);
- });
+ mObserver.onMotionEvent(downEvent, downEvent, 0);
verify(mCallback).onGestureCancelled(eq(0L),
mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(downEvent)));
@@ -108,9 +104,7 @@
final int timeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
mContext) + 100;
- mInstrumentation.runOnMainSync(() -> {
- mObserver.onMotionEvent(downEvent, downEvent, 0);
- });
+ mObserver.onMotionEvent(downEvent, downEvent, 0);
verify(mCallback, timeout(timeoutMillis)).onGestureCancelled(eq(downEvent.getDownTime()),
mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(downEvent)));
@@ -121,14 +115,12 @@
public void sendEventsOfSwiping_onGestureCompleted() {
final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
DEFAULT_X, DEFAULT_Y);
- final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop() + 1;
final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
DEFAULT_X + swipeDistance, DEFAULT_Y + swipeDistance);
- mInstrumentation.runOnMainSync(() -> {
- mObserver.onMotionEvent(downEvent, downEvent, 0);
- mObserver.onMotionEvent(moveEvent, moveEvent, 0);
- });
+ mObserver.onMotionEvent(downEvent, downEvent, 0);
+ mObserver.onMotionEvent(moveEvent, moveEvent, 0);
verify(mCallback).onGestureCompleted(eq(MagnificationGestureMatcher.GESTURE_SWIPE),
eq(downEvent.getDownTime()), mEventInfoArgumentCaptor.capture(),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
index 01631bf21..0ca631e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
@@ -78,7 +78,7 @@
@Test
public void sendSwipeEvent_onGestureCompleted() {
- final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop() + 1;
final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
DEFAULT_X, DEFAULT_Y);
final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
new file mode 100644
index 0000000..162d2a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.accessibility.magnification;
+
+import static com.android.server.accessibility.utils.TouchEventGenerator.movePointer;
+import static com.android.server.accessibility.utils.TouchEventGenerator.twoPointersDownEvents;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.server.accessibility.utils.TouchEventGenerator;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+/**
+ * Tests for {@link TwoFingersDownOrSwipe}.
+ */
+public class TwoFingersDownOrSwipeTest {
+
+ private static final float DEFAULT_X = 100f;
+ private static final float DEFAULT_Y = 100f;
+
+ private static float sSwipeMinDistance;
+ private static int sTimeoutMillis;
+ private static Context sContext;
+
+ private GesturesObserver mGesturesObserver;
+ @Mock
+ private GesturesObserver.Listener mListener;
+
+ @BeforeClass
+ public static void setupOnce() {
+ sContext = InstrumentationRegistry.getContext();
+ sTimeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
+ sContext) + 100;
+ sSwipeMinDistance = ViewConfiguration.get(sContext).getScaledTouchSlop() + 1;
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mGesturesObserver = new GesturesObserver(mListener, new TwoFingersDownOrSwipe(sContext));
+ }
+
+ @Test
+ public void sendSingleDownEvent_GestureCanceledAfterTimeout() {
+ final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
+ DEFAULT_X, DEFAULT_Y);
+
+ mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
+
+ verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
+ any(MotionEvent.class), eq(0));
+ }
+
+ @Test
+ public void sendTwoFingerDownEvent_onGestureCompleted() {
+ final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+ new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+
+ for (MotionEvent event : downEvents) {
+ mGesturesObserver.onMotionEvent(event, event, 0);
+ }
+
+ verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
+ MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, downEvents.get(1),
+ downEvents.get(1), 0);
+ }
+
+ @Test
+ public void sendSingleTapEvent_onGestureCancelled() {
+ final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
+ DEFAULT_X, DEFAULT_Y);
+ final MotionEvent upEvent = TouchEventGenerator.upEvent(Display.DEFAULT_DISPLAY,
+ DEFAULT_X, DEFAULT_Y);
+
+ mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
+ mGesturesObserver.onMotionEvent(upEvent, upEvent, 0);
+
+ verify(mListener, after(ViewConfiguration.getDoubleTapTimeout())).onGestureCancelled(
+ any(MotionEvent.class), any(MotionEvent.class), eq(0));
+ }
+
+ @Test
+ public void firstPointerMove_twoPointersDown_onGestureCompleted() {
+ final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+ new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+ for (MotionEvent event : downEvents) {
+ mGesturesObserver.onMotionEvent(event, event, 0);
+ }
+ final MotionEvent moveEvent = movePointer(downEvents.get(1), 0, sSwipeMinDistance, 0);
+
+ mGesturesObserver.onMotionEvent(moveEvent, moveEvent, 0);
+
+ verify(mListener).onGestureCompleted(
+ MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, moveEvent,
+ moveEvent, 0);
+ }
+
+ @Test
+ public void secondPointerMove_twoPointersDown_onGestureCompleted() {
+ final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+ new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+ for (MotionEvent event : downEvents) {
+ mGesturesObserver.onMotionEvent(event, event, 0);
+ }
+ final MotionEvent moveEvent = movePointer(downEvents.get(1), 1, sSwipeMinDistance, 0);
+
+ mGesturesObserver.onMotionEvent(moveEvent, moveEvent, 0);
+
+ verify(mListener).onGestureCompleted(
+ MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, moveEvent,
+ moveEvent, 0);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
deleted file mode 100644
index ed8dc4e..0000000
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
+++ /dev/null
@@ -1,114 +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.
- */
-
-package com.android.server.accessibility.magnification;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.view.Display;
-import android.view.MotionEvent;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.server.accessibility.utils.TouchEventGenerator;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link TwoFingersDown}.
- */
-public class TwoFingersDownTest {
-
- private static final float DEFAULT_X = 100f;
- private static final float DEFAULT_Y = 100f;
-
- private static Context sContext;
- private static int sTimeoutMillis;
-
- private Context mContext;
- private GesturesObserver mGesturesObserver;
- @Mock
- private GesturesObserver.Listener mListener;
-
- @BeforeClass
- public static void setupOnce() {
- sContext = InstrumentationRegistry.getContext();
- sTimeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
- sContext) + 100;
- }
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
- MockitoAnnotations.initMocks(this);
- mGesturesObserver = new GesturesObserver(mListener, new TwoFingersDown(mContext));
- }
-
- @Test
- public void sendSingleDownEvent_GestureCanceledAfterTimeout() {
- final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
- DEFAULT_X, DEFAULT_Y);
-
- mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
-
- verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
- any(MotionEvent.class), eq(0));
- }
-
- @Test
- public void sendTwoFingerDownEvent_onGestureCompleted() {
- final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
- DEFAULT_X, DEFAULT_Y);
- final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
- defPointerCoords.x = DEFAULT_X;
- defPointerCoords.y = DEFAULT_Y;
- final MotionEvent.PointerCoords secondPointerCoords = new MotionEvent.PointerCoords();
- secondPointerCoords.x = DEFAULT_X + 10;
- secondPointerCoords.y = DEFAULT_Y + 10;
-
- final MotionEvent twoPointersDownEvent = TouchEventGenerator.twoPointersDownEvent(
- Display.DEFAULT_DISPLAY, defPointerCoords, secondPointerCoords);
-
- mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
- mGesturesObserver.onMotionEvent(twoPointersDownEvent, twoPointersDownEvent, 0);
-
- verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
- MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN, twoPointersDownEvent,
- twoPointersDownEvent, 0);
- }
-
- @Test
- public void sendSingleTapEvent_onGestureCancelled() {
- final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
- DEFAULT_X, DEFAULT_Y);
- final MotionEvent upEvent = TouchEventGenerator.upEvent(Display.DEFAULT_DISPLAY,
- DEFAULT_X, DEFAULT_Y);
-
- mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
- mGesturesObserver.onMotionEvent(upEvent, upEvent, 0);
-
- verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
- any(MotionEvent.class), eq(0));
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index 4b7ebbc..b9498d6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -24,13 +24,15 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.DebugUtils;
import android.view.InputDevice;
import android.view.MotionEvent;
+import android.view.ViewConfiguration;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.EventStreamTransformation;
@@ -43,6 +45,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
import java.util.function.IntConsumer;
/**
@@ -75,7 +78,7 @@
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getContext();
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
mock(WindowMagnificationManager.Callback.class));
mMockConnection = new MockWindowMagnificationConnection();
@@ -100,8 +103,8 @@
* Covers following paths to get to and back between each state and {@link #STATE_IDLE}.
* <p>
* <br> IDLE -> SHOW_MAGNIFIER [label="a11y\nbtn"]
- * <br> SHOW_MAGNIFIER -> TWO_FINGER_DOWN [label="2hold"]
- * <br> TWO_FINGER_DOWN -> SHOW_MAGNIFIER [label="release"]
+ * <br> SHOW_MAGNIFIER -> TWO_FINGERS_DOWN [label="2hold"]
+ * <br> TWO_FINGERS_DOWN -> SHOW_MAGNIFIER [label="release"]
* <br> SHOW_MAGNIFIER -> IDLE [label="a11y\nbtn"]
* <br> IDLE -> SHOW_MAGNIFIER_TRIPLE_TAP [label="3tap"]
* <br> SHOW_MAGNIFIER_TRIPLE_TAP -> IDLE [label="3tap"]
@@ -112,18 +115,16 @@
*/
@Test
public void testEachState_isReachableAndRecoverable() {
- InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- forEachState(state -> {
- goFromStateIdleTo(state);
- assertIn(state);
- returnToNormalFrom(state);
- try {
- assertIn(STATE_IDLE);
- } catch (AssertionError e) {
- throw new AssertionError("Failed while testing state " + stateToString(state),
- e);
- }
- });
+ forEachState(state -> {
+ goFromStateIdleTo(state);
+ assertIn(state);
+ returnToNormalFrom(state);
+ try {
+ assertIn(STATE_IDLE);
+ } catch (AssertionError e) {
+ throw new AssertionError("Failed while testing state " + stateToString(state),
+ e);
+ }
});
}
@@ -209,10 +210,19 @@
case STATE_TWO_FINGERS_DOWN: {
goFromStateIdleTo(STATE_SHOW_MAGNIFIER_SHORTCUT);
final Rect frame = mMockConnection.getMirrorWindowFrame();
- send(downEvent(frame.centerX(), frame.centerY()));
- //Second finger is outside the window.
- send(twoPointerDownEvent(new float[]{frame.centerX(), frame.centerX() + 10},
- new float[]{frame.centerY(), frame.centerY() + 10}));
+ final PointF firstPointerDown = new PointF(frame.centerX(), frame.centerY());
+ // The second finger is outside the window.
+ final PointF secondPointerDown = new PointF(frame.right + 10,
+ frame.bottom + 10);
+ final List<MotionEvent> motionEvents =
+ TouchEventGenerator.twoPointersDownEvents(DISPLAY_0,
+ firstPointerDown, secondPointerDown);
+ for (MotionEvent downEvent: motionEvents) {
+ send(downEvent);
+ }
+ // Wait for two-finger down gesture completed.
+ Thread.sleep(ViewConfiguration.getDoubleTapTimeout());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
break;
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
@@ -301,16 +311,6 @@
send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
}
- private MotionEvent twoPointerDownEvent(float[] x, float[] y) {
- final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
- defPointerCoords.x = x[0];
- defPointerCoords.y = y[0];
- final MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
- pointerCoords.x = x[1];
- pointerCoords.y = y[1];
- return TouchEventGenerator.twoPointersDownEvent(DISPLAY_0, defPointerCoords, pointerCoords);
- }
-
private String stateDump() {
return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
index a05881f..fbcde53 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
@@ -19,16 +19,19 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
-import static android.view.MotionEvent.PointerCoords;
+import android.graphics.PointF;
import android.os.SystemClock;
import android.view.InputDevice;
import android.view.MotionEvent;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* generates {@link MotionEvent} with source {@link InputDevice#SOURCE_TOUCHSCREEN}
- *
*/
public class TouchEventGenerator {
@@ -39,44 +42,68 @@
public static MotionEvent moveEvent(int displayId, float x, float y) {
return generateSingleTouchEvent(displayId, ACTION_MOVE, x, y);
}
+
public static MotionEvent upEvent(int displayId, float x, float y) {
return generateSingleTouchEvent(displayId, ACTION_UP, x, y);
}
- public static MotionEvent twoPointersDownEvent(int displayId, PointerCoords defPointerCoords,
- PointerCoords pointerCoords) {
- return generateTwoPointersEvent(displayId, ACTION_POINTER_DOWN, defPointerCoords,
- pointerCoords);
- }
-
private static MotionEvent generateSingleTouchEvent(int displayId, int action, float x,
float y) {
- final long downTime = SystemClock.uptimeMillis();
- final MotionEvent ev = MotionEvent.obtain(downTime, downTime,
- action, x, y, 0);
- ev.setDisplayId(displayId);
- ev.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- return ev;
+ return generateMultiplePointersEvent(displayId, action, new PointF(x, y));
}
- private static MotionEvent generateTwoPointersEvent(int displayId, int action,
- PointerCoords defPointerCoords, PointerCoords pointerCoords) {
- final long downTime = SystemClock.uptimeMillis();
- MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
- defPointerProperties.id = 0;
- defPointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
- MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
- pointerProperties.id = 1;
- pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+ /**
+ * Creates a list of {@link MotionEvent} with given pointers location.
+ *
+ * @param displayId the display id
+ * @param pointF1 location on the screen of the second pointer.
+ * @param pointF2 location on the screen of the second pointer.
+ * @return a list of {@link MotionEvent} with {@link MotionEvent#ACTION_DOWN} and {@link
+ * MotionEvent#ACTION_POINTER_DOWN}.
+ */
+ public static List<MotionEvent> twoPointersDownEvents(int displayId, PointF pointF1,
+ PointF pointF2) {
+ final List<MotionEvent> downEvents = new ArrayList<>();
+ final MotionEvent downEvent = generateMultiplePointersEvent(displayId,
+ MotionEvent.ACTION_DOWN, pointF1);
+ downEvents.add(downEvent);
+ final int actionIndex = 1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int action = ACTION_POINTER_DOWN | actionIndex;
+
+ final MotionEvent twoPointersDownEvent = generateMultiplePointersEvent(displayId, action,
+ pointF1, pointF2);
+ downEvents.add(twoPointersDownEvent);
+ return downEvents;
+ }
+
+ private static MotionEvent generateMultiplePointersEvent(int displayId, int action,
+ PointF... pointFs) {
+ final int length = pointFs.length;
+ final MotionEvent.PointerCoords[] pointerCoordsArray =
+ new MotionEvent.PointerCoords[length];
+ final MotionEvent.PointerProperties[] pointerPropertiesArray =
+ new MotionEvent.PointerProperties[length];
+ for (int i = 0; i < length; i++) {
+ MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
+ pointerCoords.x = pointFs[i].x;
+ pointerCoords.y = pointFs[i].y;
+ pointerCoordsArray[i] = pointerCoords;
+
+ MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
+ pointerProperties.id = i;
+ pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+ pointerPropertiesArray[i] = pointerProperties;
+ }
+
+ final long downTime = SystemClock.uptimeMillis();
final MotionEvent ev = MotionEvent.obtain(
/* downTime */ downTime,
/* eventTime */ downTime,
/* action */ action,
- /* pointerCount */ 2,
- /* pointerProperties */ new MotionEvent.PointerProperties[] {
- defPointerProperties, pointerProperties},
- /* pointerCoords */ new PointerCoords[] { defPointerCoords, pointerCoords },
+ /* pointerCount */ length,
+ /* pointerProperties */ pointerPropertiesArray,
+ /* pointerCoords */ pointerCoordsArray,
/* metaState */ 0,
/* buttonState */ 0,
/* xPrecision */ 1.0f,
@@ -88,4 +115,65 @@
ev.setDisplayId(displayId);
return ev;
}
+
+ /**
+ * Generates a move event that moves the pointer of the original event with given index.
+ * The original event should not be up event and we don't support
+ * {@link MotionEvent#ACTION_POINTER_UP} now.
+ *
+ * @param originalEvent the move or down event
+ * @param pointerIndex the index of the pointer we want to move.
+ * @param offsetX the offset in X coordinate.
+ * @param offsetY the offset in Y coordinate.
+ * @return a motion event with move action.
+ */
+ public static MotionEvent movePointer(MotionEvent originalEvent, int pointerIndex,
+ float offsetX, float offsetY) {
+ if (originalEvent.getActionMasked() == ACTION_UP) {
+ throw new IllegalArgumentException("No pointer is on the screen");
+ }
+
+ if (originalEvent.getActionMasked() == ACTION_POINTER_UP) {
+ throw new IllegalArgumentException("unsupported yet,please implement it first");
+ }
+
+ final int pointerCount = originalEvent.getPointerCount();
+ if (pointerIndex >= pointerCount) {
+ throw new IllegalArgumentException(
+ pointerIndex + "is not available with pointer count" + pointerCount);
+ }
+ final int action = MotionEvent.ACTION_MOVE;
+ final MotionEvent.PointerProperties[] pp = new MotionEvent.PointerProperties[pointerCount];
+ for (int i = 0; i < pointerCount; i++) {
+ MotionEvent.PointerProperties pointerProperty = new MotionEvent.PointerProperties();
+ originalEvent.getPointerProperties(i, pointerProperty);
+ pp[i] = pointerProperty;
+ }
+
+ final MotionEvent.PointerCoords[] pc = new MotionEvent.PointerCoords[pointerCount];
+ for (int i = 0; i < pointerCount; i++) {
+ MotionEvent.PointerCoords pointerCoord = new MotionEvent.PointerCoords();
+ originalEvent.getPointerCoords(i, pointerCoord);
+ pc[i] = pointerCoord;
+ }
+ pc[pointerIndex].x += offsetX;
+ pc[pointerIndex].y += offsetY;
+ final MotionEvent ev = MotionEvent.obtain(
+ /* downTime */ originalEvent.getDownTime(),
+ /* eventTime */ SystemClock.uptimeMillis(),
+ /* action */ action,
+ /* pointerCount */ 2,
+ /* pointerProperties */ pp,
+ /* pointerCoords */ pc,
+ /* metaState */ 0,
+ /* buttonState */ 0,
+ /* xPrecision */ 1.0f,
+ /* yPrecision */ 1.0f,
+ /* deviceId */ 0,
+ /* edgeFlags */ 0,
+ /* source */ originalEvent.getSource(),
+ /* flags */ originalEvent.getFlags());
+ ev.setDisplayId(originalEvent.getDisplayId());
+ return ev;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
index 488e5cd..1870df9 100644
--- a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
@@ -30,6 +30,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -59,6 +60,7 @@
}
@Test
+ @Ignore("b/180015146")
public void testAwaitCompletion() throws Exception {
final CountDownLatch readyLatch = new CountDownLatch(2);
final CountDownLatch startLatch = new CountDownLatch(1);
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index a078a77..26a549d 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -21,8 +21,10 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertThrows;
+import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.DeviceStateRequest;
import android.hardware.devicestate.IDeviceStateManagerCallback;
import android.os.Binder;
@@ -33,10 +35,13 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Optional;
@@ -70,14 +75,14 @@
public void baseStateChanged() {
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
}
@@ -89,21 +94,21 @@
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
mPolicy.resumeConfigure();
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@@ -116,7 +121,7 @@
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@@ -129,16 +134,19 @@
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
- public void supportedStatesChanged() {
+ public void supportedStatesChanged() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
@@ -146,27 +154,44 @@
// supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+
+ assertArrayEquals(callback.getLastNotifiedInfo().supportedStates,
+ new int[] { DEFAULT_DEVICE_STATE.getIdentifier() });
}
@Test
- public void supportedStatesChanged_unsupportedBaseState() {
+ public void supportedStatesChanged_statesRemainSame() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
- mProvider.notifySupportedDeviceStates(new DeviceState[]{ OTHER_DEVICE_STATE });
+ mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
+ OTHER_DEVICE_STATE });
- // The current requested state is cleared because it is no longer supported.
+ // The current committed and requests states do not change because the current state remains
+ // supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState(), Optional.empty());
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
- mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+ // The callback wasn't notified about a change in supported states as the states have not
+ // changed.
+ assertNull(callback.getLastNotifiedInfo());
+ }
- assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ @Test
+ public void getDeviceStateInfo() throws RemoteException {
+ DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+ assertNotNull(info);
+ assertArrayEquals(info.supportedStates,
+ new int[] { DEFAULT_DEVICE_STATE.getIdentifier(),
+ OTHER_DEVICE_STATE.getIdentifier() });
+ assertEquals(info.baseState, DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(info.currentState, DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
@@ -175,41 +200,33 @@
mService.getBinderService().registerCallback(callback);
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
- assertNotNull(callback.getLastNotifiedValue());
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ OTHER_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
OTHER_DEVICE_STATE.getIdentifier());
mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
DEFAULT_DEVICE_STATE.getIdentifier());
mPolicy.blockConfigure();
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
// The callback should not have been notified of the state change as the policy is still
// pending callback.
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
DEFAULT_DEVICE_STATE.getIdentifier());
mPolicy.resumeConfigure();
// Now that the policy is finished processing the callback should be notified of the state
// change.
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
OTHER_DEVICE_STATE.getIdentifier());
- }
-
- @Test
- public void registerCallback_emitsInitialValue() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
- mService.getBinderService().registerCallback(callback);
- assertNotNull(callback.getLastNotifiedValue());
- assertEquals(callback.getLastNotifiedValue().intValue(),
- DEFAULT_DEVICE_STATE.getIdentifier());
- }
-
- @Test
- public void getSupportedDeviceStates() throws RemoteException {
- final int[] expectedStates = new int[] { 0, 1 };
- assertEquals(mService.getBinderService().getSupportedDeviceStates(), expectedStates);
+ assertEquals(callback.getLastNotifiedInfo().currentState,
+ OTHER_DEVICE_STATE.getIdentifier());
}
@Test
@@ -228,11 +245,16 @@
TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
+ assertNotNull(callback.getLastNotifiedInfo());
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
+ OTHER_DEVICE_STATE.getIdentifier());
mService.getBinderService().cancelRequest(token);
@@ -240,10 +262,15 @@
TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state once the override is cleared.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertFalse(mService.getOverrideState().isPresent());
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
+
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
@@ -263,7 +290,7 @@
// Committed state changes as there is a requested override.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
@@ -275,7 +302,7 @@
TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state once the override is cleared.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
assertFalse(mService.getOverrideState().isPresent());
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
@@ -297,7 +324,7 @@
TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
@@ -310,7 +337,7 @@
// Committed state is set back to the requested state as the override state is no longer
// supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertFalse(mService.getOverrideState().isPresent());
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
@@ -348,6 +375,10 @@
});
}
+ private static void assertArrayEquals(int[] expected, int[] actual) {
+ Assert.assertTrue(Arrays.equals(expected, actual));
+ }
+
private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
private final DeviceStateProvider mProvider;
private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
@@ -429,12 +460,14 @@
public static final int STATUS_SUSPENDED = 2;
public static final int STATUS_CANCELED = 3;
- private Integer mLastNotifiedValue;
+ @Nullable
+ private DeviceStateInfo mLastNotifiedInfo;
+ private boolean mNotifiedOfChangeInSupportedStates;
private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
@Override
- public void onDeviceStateChanged(int deviceState) {
- mLastNotifiedValue = deviceState;
+ public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+ mLastNotifiedInfo = info;
}
@Override
@@ -453,8 +486,8 @@
}
@Nullable
- Integer getLastNotifiedValue() {
- return mLastNotifiedValue;
+ DeviceStateInfo getLastNotifiedInfo() {
+ return mLastNotifiedInfo;
}
int getLastNotifiedStatus(IBinder requestToken) {
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java
index 27fce3c..912da94 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java
@@ -45,7 +45,7 @@
public void testWriteRead() throws Exception {
long expectedModifiedDate = 1234567890;
PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
- config.lastModifiedDate = expectedModifiedDate;
+ config.lastModifiedMillis = expectedModifiedDate;
config.updatedFontDirs.add("~~abc");
config.updatedFontDirs.add("~~def");
@@ -65,7 +65,7 @@
PersistentSystemFontConfig.Config another = new PersistentSystemFontConfig.Config();
PersistentSystemFontConfig.loadFromXml(bais, another);
- assertThat(another.lastModifiedDate).isEqualTo(expectedModifiedDate);
+ assertThat(another.lastModifiedMillis).isEqualTo(expectedModifiedDate);
assertThat(another.updatedFontDirs).containsExactly("~~abc", "~~def");
assertThat(another.fontFamilies).containsExactly(fontFamily);
}
@@ -82,7 +82,7 @@
new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
PersistentSystemFontConfig.loadFromXml(bais, config);
- assertThat(config.lastModifiedDate).isEqualTo(0);
+ assertThat(config.lastModifiedMillis).isEqualTo(0);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index 7771afc..843296e 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -151,7 +151,7 @@
FakeFontFileParser parser = new FakeFontFileParser();
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
- config.lastModifiedDate = expectedModifiedDate;
+ config.lastModifiedMillis = expectedModifiedDate;
writeConfig(config, mConfigFile);
UpdatableFontDir dirForPreparation = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
@@ -507,7 +507,7 @@
File readonlyFile = new File(readonlyDir, "readonly_config.xml");
PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
- config.lastModifiedDate = expectedModifiedDate;
+ config.lastModifiedMillis = expectedModifiedDate;
writeConfig(config, readonlyFile);
assertThat(readonlyDir.setWritable(false, false)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index f2254a9..c08857c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -74,8 +74,6 @@
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
mHdmiControlService = new HdmiControlService(mContextSpy) {
@Override
AudioManager getAudioManager() {
@@ -106,15 +104,11 @@
protected void writeStringSystemProperty(String key, String value) {
// do nothing
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 44418ce..50ba761 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -76,8 +76,6 @@
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
HdmiControlService hdmiControlService =
new HdmiControlService(mContextSpy) {
@Override
@@ -112,11 +110,6 @@
Looper getServiceLooper() {
return mTestLooper.getLooper();
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -128,6 +121,7 @@
mHdmiCecLocalDeviceAudioSystem.init();
Looper looper = mTestLooper.getLooper();
hdmiControlService.setIoLooper(looper);
+ hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index d454d87..aa5bc93 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -77,8 +77,6 @@
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
HdmiControlService hdmiControlService =
new HdmiControlService(mContextSpy) {
@Override
@@ -113,15 +111,11 @@
Looper getServiceLooper() {
return mTestLooper.getLooper();
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
Looper looper = mTestLooper.getLooper();
hdmiControlService.setIoLooper(looper);
+ hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index 7cb72c4..ef7b274 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -86,8 +86,6 @@
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
mHdmiControlService = new HdmiControlService(mContextSpy) {
@Override
AudioManager getAudioManager() {
@@ -118,15 +116,11 @@
protected void writeStringSystemProperty(String key, String value) {
// do nothing
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
index 9bf95c0..678f8b2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
@@ -106,8 +106,6 @@
PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
mIThermalServiceMock, new Handler(mMyLooper));
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@Override
@@ -133,16 +131,12 @@
protected PowerManager getPowerManager() {
return powerManager;
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
mHdmiCecLocalDeviceTv.init();
mHdmiControlService.setIoLooper(mMyLooper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index eedbc95..6bb148d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -98,8 +98,6 @@
PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
mIThermalServiceMock, new Handler(mMyLooper));
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@Override
@@ -188,17 +186,13 @@
protected PowerManager getPowerManager() {
return powerManager;
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
HdmiControlManager.VOLUME_CONTROL_ENABLED);
mMyLooper = mTestLooper.getLooper();
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index b11ac24..915392e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -87,7 +87,6 @@
mMyLooper = mTestLooper.getLooper();
PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
mIThermalServiceMock, new Handler(mMyLooper));
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@@ -136,15 +135,11 @@
protected PowerManager getPowerManager() {
return powerManager;
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService);
mHdmiCecLocalDevicePlayback.init();
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
mHdmiControlService.setIoLooper(mMyLooper);
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 0717112..b3f0085 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -128,8 +128,6 @@
Context context = InstrumentationRegistry.getTargetContext();
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
mHdmiControlService =
new HdmiControlService(context) {
@Override
@@ -163,13 +161,9 @@
void wakeUp() {
mWakeupMessageReceived = true;
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mHdmiControlService.setIoLooper(mTestLooper.getLooper());
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
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 4623eb5..4b3ef2f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -81,8 +81,6 @@
PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
mIThermalServiceMock, new Handler(mMyLooper));
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@Override
@@ -119,16 +117,12 @@
AudioManager getAudioManager() {
return mAudioManager;
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
mHdmiCecLocalDeviceTv.init();
mHdmiControlService.setIoLooper(mMyLooper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index 06373c2..1c7ff42 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -62,12 +62,12 @@
private FakeNativeWrapper mNativeWrapper;
private TestLooper mTestLooper = new TestLooper();
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
- private int mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_B;
@Mock
private IPowerManager mIPowerManagerMock;
@Mock
private IThermalService mIThermalServiceMock;
private HdmiControlService mHdmiControlService;
+ private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
@Before
public void setUp() throws Exception {
@@ -81,8 +81,6 @@
when(contextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(contextSpy);
-
mHdmiControlService = new HdmiControlService(contextSpy) {
@Override
boolean isControlEnabled() {
@@ -100,33 +98,24 @@
}
@Override
- int getCecVersion() {
- return mHdmiCecVersion;
- }
-
- @Override
boolean isPowerStandby() {
return false;
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mHdmiControlService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
- HdmiCecLocalDevicePlayback hdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(
+ mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
- hdmiCecLocalDevicePlayback.init();
+ mHdmiCecLocalDevicePlayback.init();
mHdmiControlService.setIoLooper(myLooper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(contextSpy));
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
mHdmiControlService.setCecController(hdmiCecController);
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
- mLocalDevices.add(hdmiCecLocalDevicePlayback);
+ mLocalDevices.add(mHdmiCecLocalDevicePlayback);
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
@@ -188,77 +177,84 @@
@Test
public void setPowerStatus_doesntSendBroadcast_1_4() {
+ setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
mTestLooper.dispatchAll();
HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+ mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
HdmiControlManager.POWER_STATUS_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
@Test
public void setPowerStatus_transient_doesntSendBroadcast_1_4() {
+ setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
mHdmiCecPowerStatusController.setPowerStatus(
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
mTestLooper.dispatchAll();
HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+ mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
@Test
public void setPowerStatus_fast_transient_doesntSendBroadcast_1_4() {
+ setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
mHdmiCecPowerStatusController.setPowerStatus(
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
mTestLooper.dispatchAll();
HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+ mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
@Test
public void setPowerStatus_sendsBroadcast_2_0() {
- mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+ setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
mTestLooper.dispatchAll();
HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+ mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
HdmiControlManager.POWER_STATUS_ON);
assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
}
@Test
public void setPowerStatus_transient_sendsBroadcast_2_0() {
- mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+ setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiCecPowerStatusController.setPowerStatus(
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
mTestLooper.dispatchAll();
HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+ mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
}
@Test
public void setPowerStatus_fast_transient_doesntSendBroadcast_2_0() {
- mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+ setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiCecPowerStatusController.setPowerStatus(
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
mTestLooper.dispatchAll();
HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
- Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+ mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
}
+
+ private void setCecVersion(int version) {
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, version);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 32a7048..47f3bf9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -19,6 +19,7 @@
import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
+import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static com.google.common.truth.Truth.assertThat;
@@ -44,12 +45,12 @@
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -68,14 +69,64 @@
@RunWith(JUnit4.class)
public class HdmiControlServiceTest {
- private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDeviceSource {
+ private class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
private boolean mCanGoToStandby;
private boolean mIsStandby;
private boolean mIsDisabled;
- protected HdmiCecLocalDeviceMyDevice(HdmiControlService service, int deviceType) {
- super(service, deviceType);
+ MockPlaybackDevice(HdmiControlService service) {
+ super(service);
+ }
+
+ @Override
+ protected void onAddressAllocated(int logicalAddress, int reason) {}
+
+ @Override
+ protected int getPreferredAddress() {
+ return 0;
+ }
+
+ @Override
+ protected void setPreferredAddress(int addr) {}
+
+ @Override
+ protected boolean canGoToStandby() {
+ return mCanGoToStandby;
+ }
+
+ @Override
+ protected void disableDevice(
+ boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
+ mIsDisabled = true;
+ originalCallback.onCleared(this);
+ }
+
+ @Override
+ protected void onStandby(boolean initiatedByCec, int standbyAction) {
+ mIsStandby = true;
+ }
+
+ protected boolean isStandby() {
+ return mIsStandby;
+ }
+
+ protected boolean isDisabled() {
+ return mIsDisabled;
+ }
+
+ protected void setCanGoToStandby(boolean canGoToStandby) {
+ mCanGoToStandby = canGoToStandby;
+ }
+ }
+ private class MockAudioSystemDevice extends HdmiCecLocalDeviceAudioSystem {
+
+ private boolean mCanGoToStandby;
+ private boolean mIsStandby;
+ private boolean mIsDisabled;
+
+ MockAudioSystemDevice(HdmiControlService service) {
+ super(service);
}
@Override
@@ -123,8 +174,8 @@
private Context mContextSpy;
private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
- private HdmiCecLocalDeviceMyDevice mMyAudioSystemDevice;
- private HdmiCecLocalDeviceMyDevice mMyPlaybackDevice;
+ private MockAudioSystemDevice mAudioSystemDevice;
+ private MockPlaybackDevice mPlaybackDevice;
private FakeNativeWrapper mNativeWrapper;
private Looper mMyLooper;
private TestLooper mTestLooper = new TestLooper();
@@ -144,6 +195,7 @@
PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
mIThermalServiceMock, null);
when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+ when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
@@ -157,21 +209,17 @@
@Override
protected void writeStringSystemProperty(String key, String value) {
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
mMyLooper = mTestLooper.getLooper();
- mMyAudioSystemDevice =
- new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_AUDIO_SYSTEM);
- mMyPlaybackDevice = new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_PLAYBACK);
- mMyAudioSystemDevice.init();
- mMyPlaybackDevice.init();
+ mAudioSystemDevice = new MockAudioSystemDevice(mHdmiControlService);
+ mPlaybackDevice = new MockPlaybackDevice(mHdmiControlService);
+ mAudioSystemDevice.init();
+ mPlaybackDevice.init();
mHdmiControlService.setIoLooper(mMyLooper);
+ mHdmiControlService.setHdmiCecConfig(hdmiCecConfig);
+ mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
@@ -180,8 +228,8 @@
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
- mLocalDevices.add(mMyAudioSystemDevice);
- mLocalDevices.add(mMyPlaybackDevice);
+ mLocalDevices.add(mAudioSystemDevice);
+ mLocalDevices.add(mPlaybackDevice);
mHdmiPortInfo = new HdmiPortInfo[4];
mHdmiPortInfo[0] =
new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false);
@@ -192,6 +240,9 @@
mHdmiPortInfo[3] =
new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
mNativeWrapper.setPortInfo(mHdmiPortInfo);
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
mHdmiControlService.initService();
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
@@ -201,13 +252,13 @@
@Test
public void onStandby_notByCec_cannotGoToStandby() {
mStandbyMessageReceived = false;
- mMyPlaybackDevice.setCanGoToStandby(false);
+ mPlaybackDevice.setCanGoToStandby(false);
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
- assertTrue(mMyPlaybackDevice.isStandby());
- assertTrue(mMyAudioSystemDevice.isStandby());
- assertFalse(mMyPlaybackDevice.isDisabled());
- assertFalse(mMyAudioSystemDevice.isDisabled());
+ assertTrue(mPlaybackDevice.isStandby());
+ assertTrue(mAudioSystemDevice.isStandby());
+ assertFalse(mPlaybackDevice.isDisabled());
+ assertFalse(mAudioSystemDevice.isDisabled());
}
@Test
@@ -215,10 +266,10 @@
mStandbyMessageReceived = true;
mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
- assertTrue(mMyPlaybackDevice.isStandby());
- assertTrue(mMyAudioSystemDevice.isStandby());
- assertTrue(mMyPlaybackDevice.isDisabled());
- assertTrue(mMyAudioSystemDevice.isDisabled());
+ assertTrue(mPlaybackDevice.isStandby());
+ assertTrue(mAudioSystemDevice.isStandby());
+ assertTrue(mPlaybackDevice.isDisabled());
+ assertTrue(mAudioSystemDevice.isDisabled());
}
@Test
@@ -275,6 +326,7 @@
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ mTestLooper.dispatchAll();
mHdmiControlService.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
mNativeWrapper.clearResultMessages();
@@ -555,8 +607,8 @@
HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
- mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
- mMyPlaybackDevice.getDeviceFeatures());
+ mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+ mPlaybackDevice.getDeviceFeatures());
assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
}
@@ -573,8 +625,8 @@
HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
- mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
- mMyPlaybackDevice.getDeviceFeatures());
+ mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+ mPlaybackDevice.getDeviceFeatures());
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportFeatures);
}
@@ -590,8 +642,8 @@
HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
- mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
- mMyPlaybackDevice.getDeviceFeatures());
+ mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+ mPlaybackDevice.getDeviceFeatures());
assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
}
@@ -612,41 +664,42 @@
assertEquals(runnerUid, Binder.getCallingWorkSourceUid());
}
- @Ignore("b/180499471")
@Test
public void initCecVersion_limitToMinimumSupportedVersion() {
+ mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
+ Log.e("MARVIN", "set setting CEC");
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
- mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
- mHdmiControlService.initService();
+ mTestLooper.dispatchAll();
assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
}
- @Ignore("b/180499471")
@Test
public void initCecVersion_limitToAtLeast1_4() {
+ Log.e("MARVIN", "set HAL CEC to 0");
+ mNativeWrapper.setCecVersion(0x0);
+ Log.e("MARVIN", "set setting CEC to 2");
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
- mNativeWrapper.setCecVersion(0x0);
- mHdmiControlService.initService();
+ mTestLooper.dispatchAll();
assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
}
- @Ignore("b/180499471")
@Test
public void initCecVersion_useHighestMatchingVersion() {
+ mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ Log.e("MARVIN", "set setting CEC");
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
- mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
- mHdmiControlService.initService();
+ mTestLooper.dispatchAll();
assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
HdmiControlManager.HDMI_CEC_VERSION_2_0);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index b8dfd56..605f781 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -84,8 +84,6 @@
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
mHdmiControlService = new HdmiControlService(mContextSpy) {
@Override
AudioManager getAudioManager() {
@@ -116,15 +114,11 @@
protected void writeStringSystemProperty(String key, String value) {
// do nothing
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
+ mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
@@ -185,6 +179,7 @@
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ mTestLooper.dispatchAll();
sendMessageFromPlaybackDevice(ADDR_PLAYBACK_1, 0x1000);
reportPowerStatus(ADDR_PLAYBACK_1, true, HdmiControlManager.POWER_STATUS_ON);
mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index f9160ab..e82c788 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -65,8 +65,6 @@
Context context = InstrumentationRegistry.getTargetContext();
- HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
HdmiControlService hdmiControlService = new HdmiControlService(context) {
@Override
void sendCecCommand(
@@ -164,15 +162,11 @@
int pathToPortId(int path) {
return -1;
}
-
- @Override
- protected HdmiCecConfig getHdmiCecConfig() {
- return hdmiCecConfig;
- }
};
Looper looper = mTestLooper.getLooper();
hdmiControlService.setIoLooper(looper);
+ hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
HdmiCecController.NativeWrapper nativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
hdmiControlService, nativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 73191dc..4a42940 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -150,7 +150,7 @@
}
@Override
- public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
+ public RecoverableKeyStoreManager getRecoverableKeyStoreManager() {
return mRecoverableKeyStoreManager;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index e46ab6b..029e9a3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -45,6 +45,13 @@
import android.app.IUidObserver;
import android.app.Person;
import android.app.admin.DevicePolicyManager;
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.IAppSearchBatchResultCallback;
+import android.app.appsearch.IAppSearchManager;
+import android.app.appsearch.IAppSearchResultCallback;
+import android.app.appsearch.PackageIdentifier;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
@@ -78,6 +85,7 @@
import android.os.Bundle;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.Process;
@@ -150,6 +158,8 @@
return mMockUserManager;
case Context.DEVICE_POLICY_SERVICE:
return mMockDevicePolicyManager;
+ case Context.APP_SEARCH_SERVICE:
+ return new AppSearchManager(getTestContext(), mMockAppSearchManager);
case Context.ROLE_SERVICE:
// RoleManager is final and cannot be mocked, so we only override the inject
// accessor methods in ShortcutService.
@@ -159,6 +169,11 @@
}
@Override
+ public String getOpPackageName() {
+ return getTestContext().getOpPackageName();
+ }
+
+ @Override
public String getSystemServiceName(Class<?> serviceClass) {
return getTestContext().getSystemServiceName(serviceClass);
}
@@ -601,6 +616,123 @@
}
}
+ protected class MockAppSearchManager implements IAppSearchManager {
+
+ protected Map<String, List<PackageIdentifier>> mSchemasPackageAccessible =
+ new ArrayMap<>(1);
+
+ @Override
+ public void setSchema(String packageName, String databaseName, List<Bundle> schemaBundles,
+ List<String> schemasNotPlatformSurfaceable,
+ Map<String, List<Bundle>> schemasPackageAccessibleBundles, boolean forceOverride,
+ int userId, IAppSearchResultCallback callback) throws RemoteException {
+ for (Map.Entry<String, List<Bundle>> entry :
+ schemasPackageAccessibleBundles.entrySet()) {
+ final String key = entry.getKey();
+ final List<PackageIdentifier> packageIdentifiers;
+ if (!mSchemasPackageAccessible.containsKey(key)) {
+ packageIdentifiers = new ArrayList<>(entry.getValue().size());
+ mSchemasPackageAccessible.put(key, packageIdentifiers);
+ } else {
+ packageIdentifiers = mSchemasPackageAccessible.get(key);
+ }
+ for (int i = 0; i < entry.getValue().size(); i++) {
+ packageIdentifiers.add(new PackageIdentifier(entry.getValue().get(i)));
+ }
+ }
+ callback.onResult(AppSearchResult.newSuccessfulResult(null));
+ }
+
+ @Override
+ public void getSchema(String packageName, String databaseName, int userId,
+ IAppSearchResultCallback callback) throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void putDocuments(String packageName, String databaseName,
+ List<Bundle> documentBundles, int userId, IAppSearchBatchResultCallback callback)
+ throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void getDocuments(String packageName, String databaseName, String namespace,
+ List<String> uris, Map<String, List<String>> typePropertyPaths, int userId,
+ IAppSearchBatchResultCallback callback) throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void query(String packageName, String databaseName, String queryExpression,
+ Bundle searchSpecBundle, int userId, IAppSearchResultCallback callback)
+ throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void globalQuery(String packageName, String queryExpression, Bundle searchSpecBundle,
+ int userId, IAppSearchResultCallback callback) throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void getNextPage(long nextPageToken, int userId, IAppSearchResultCallback callback)
+ throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void invalidateNextPageToken(long nextPageToken, int userId) throws RemoteException {
+
+ }
+
+ @Override
+ public void reportUsage(String packageName, String databaseName, String namespace,
+ String uri, long usageTimeMillis, int userId, IAppSearchResultCallback callback)
+ throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void removeByUri(String packageName, String databaseName, String namespace,
+ List<String> uris, int userId, IAppSearchBatchResultCallback callback)
+ throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void removeByQuery(String packageName, String databaseName, String queryExpression,
+ Bundle searchSpecBundle, int userId, IAppSearchResultCallback callback)
+ throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public void persistToDisk(int userId) throws RemoteException {
+
+ }
+
+ @Override
+ public void initialize(int userId, IAppSearchResultCallback callback)
+ throws RemoteException {
+ ignore(callback);
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ private void ignore(IAppSearchResultCallback callback) throws RemoteException {
+ callback.onResult(AppSearchResult.newSuccessfulResult(null));
+ }
+
+ private void ignore(IAppSearchBatchResultCallback callback) throws RemoteException {
+ callback.onResult(new AppSearchBatchResult.Builder().build());
+ }
+ }
+
public static class ShortcutActivity extends Activity {
}
@@ -652,6 +784,7 @@
protected PackageManagerInternal mMockPackageManagerInternal;
protected UserManager mMockUserManager;
protected DevicePolicyManager mMockDevicePolicyManager;
+ protected MockAppSearchManager mMockAppSearchManager;
protected UserManagerInternal mMockUserManagerInternal;
protected UsageStatsManagerInternal mMockUsageStatsManagerInternal;
protected ActivityManagerInternal mMockActivityManagerInternal;
@@ -801,6 +934,7 @@
mMockPackageManagerInternal = mock(PackageManagerInternal.class);
mMockUserManager = mock(UserManager.class);
mMockDevicePolicyManager = mock(DevicePolicyManager.class);
+ mMockAppSearchManager = new MockAppSearchManager();
mMockUserManagerInternal = mock(UserManagerInternal.class);
mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
mMockActivityManagerInternal = mock(ActivityManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/pm/OWNERS b/services/tests/servicestests/src/com/android/server/pm/OWNERS
index d825dfd..e15b5f5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/pm/OWNERS
@@ -1 +1,3 @@
include /services/core/java/com/android/server/pm/OWNERS
+
+per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
new file mode 100644
index 0000000..b17085e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
@@ -0,0 +1,44 @@
+/*
+ * 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.app.appsearch.PackageIdentifier;
+import android.content.pm.AppSearchShortcutInfo;
+
+import java.util.Random;
+
+/**
+ * Tests for {@link android.app.appsearch.AppSearchManager} and relevant APIs in ShortcutManager.
+ *
+ atest -c com.android.server.pm.ShortcutManagerTest12
+ */
+public class ShortcutManagerTest12 extends BaseShortcutManagerTest {
+
+ public void testUpdateShortcutVisibility_updatesShortcutSchema() {
+
+ final byte[] cert = new byte[20];
+ new Random().nextBytes(cert);
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.updateShortcutVisibility(CALLING_PACKAGE_2, cert, true);
+ assertTrue(mMockAppSearchManager.mSchemasPackageAccessible.containsKey(
+ AppSearchShortcutInfo.SCHEMA_TYPE));
+ assertTrue(mMockAppSearchManager.mSchemasPackageAccessible.get(
+ AppSearchShortcutInfo.SCHEMA_TYPE).get(0).equals(
+ new PackageIdentifier(CALLING_PACKAGE_2, cert)));
+ });
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index fb13d87..c2b3858 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -17,10 +17,10 @@
package com.android.server.pm.parsing;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import android.apex.ApexInfo;
import android.content.Context;
@@ -39,6 +39,7 @@
import android.os.Bundle;
import android.os.FileUtils;
import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
import android.util.SparseIntArray;
import androidx.test.InstrumentationRegistry;
@@ -50,12 +51,17 @@
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.InputStream;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.function.Function;
/**
@@ -89,6 +95,8 @@
private static final int PLATFORM_VERSION = 20;
private static final int NEWER_VERSION = 30;
+ @Rule public final Expect expect = Expect.create();
+
private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename,
boolean isPlatformReleased, int expectedMinSdk) {
final String[] outError = new String[1];
@@ -553,36 +561,44 @@
@Test
public void testUsesSdk() throws Exception {
- ParsedPackage pkg =
- parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
- SparseIntArray minExtVers = pkg.getMinExtensionVersions();
+ ParsedPackage pkg;
+ SparseIntArray minExtVers;
+ pkg = parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
+ minExtVers = pkg.getMinExtensionVersions();
assertEquals(1, minExtVers.size());
- assertEquals(0, minExtVers.get(10000, -1));
+ assertEquals(0, minExtVers.get(30, -1));
- try {
- parsePackage("install_uses_sdk.apk_r5", R.raw.install_uses_sdk_r5, x -> x);
- fail("Expected parsing exception due to incompatible extension SDK version");
- } catch (PackageParser.PackageParserException expected) {
- assertEquals(PackageManager.INSTALL_FAILED_OLDER_SDK, expected.error);
- }
- try {
- parsePackage("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0, x -> x);
- fail("Expected parsing exception due to non-existent extension SDK");
- } catch (PackageParser.PackageParserException expected) {
- assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
- }
- try {
- parsePackage("install_uses_sdk.apk_r", R.raw.install_uses_sdk_r, x -> x);
- fail("Expected parsing exception due to unspecified extension SDK version");
- } catch (PackageParser.PackageParserException expected) {
- assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
- }
- try {
- parsePackage("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0, x -> x);
- fail("Expected parsing exception due to unspecified extension SDK");
- } catch (PackageParser.PackageParserException expected) {
- assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
- }
+ pkg = parsePackage("install_uses_sdk.apk_r0_s0", R.raw.install_uses_sdk_r0_s0, x -> x);
+ minExtVers = pkg.getMinExtensionVersions();
+ assertEquals(2, minExtVers.size());
+ assertEquals(0, minExtVers.get(30, -1));
+ assertEquals(0, minExtVers.get(31, -1));
+ Map<Pair<String, Integer>, Integer> appToError = new HashMap<>();
+ appToError.put(Pair.create("install_uses_sdk.apk_r5", R.raw.install_uses_sdk_r5),
+ PackageManager.INSTALL_FAILED_OLDER_SDK);
+ appToError.put(Pair.create("install_uses_sdk.apk_r0_s5", R.raw.install_uses_sdk_r0_s5),
+ PackageManager.INSTALL_FAILED_OLDER_SDK);
+
+ appToError.put(Pair.create("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0),
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+ appToError.put(Pair.create("install_uses_sdk.apk_q0_r0", R.raw.install_uses_sdk_q0_r0),
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+ appToError.put(Pair.create("install_uses_sdk.apk_r_none", R.raw.install_uses_sdk_r_none),
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+ appToError.put(Pair.create("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0),
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+
+ for (Map.Entry<Pair<String, Integer>, Integer> entry : appToError.entrySet()) {
+ String filename = entry.getKey().first;
+ int resId = entry.getKey().second;
+ int result = entry.getValue();
+ try {
+ parsePackage(filename, resId, x -> x);
+ expect.withMessage("Expected parsing error %d from %s", result, filename).fail();
+ } catch (PackageParser.PackageParserException expected) {
+ expect.that(expected.error).isEqualTo(result);
+ }
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index ddbe81c..26b34fd 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -318,7 +318,8 @@
assertTrue(pssProto.energyMeasurement.length == ENERGY_METER_COUNT);
for (int i = 0; i < pssProto.energyMeasurement.length; i++) {
assertTrue(pssProto.energyMeasurement[i].id == i);
- assertTrue(pssProto.energyMeasurement[i].timestampMs == i);
+ assertTrue(pssProto.energyMeasurement[i].timestampMs ==
+ i + mPowerStatsLogger.getStartWallTime());
assertTrue(pssProto.energyMeasurement[i].durationMs == i);
assertTrue(pssProto.energyMeasurement[i].energyUws == i);
}
@@ -359,7 +360,8 @@
assertTrue(pssProto.energyConsumerResult.length == ENERGY_CONSUMER_COUNT);
for (int i = 0; i < pssProto.energyConsumerResult.length; i++) {
assertTrue(pssProto.energyConsumerResult[i].id == i);
- assertTrue(pssProto.energyConsumerResult[i].timestampMs == i);
+ assertTrue(pssProto.energyConsumerResult[i].timestampMs ==
+ i + mPowerStatsLogger.getStartWallTime());
assertTrue(pssProto.energyConsumerResult[i].energyUws == i);
assertTrue(pssProto.energyConsumerResult[i].attribution.length
== ENERGY_CONSUMER_ATTRIBUTION_COUNT);
@@ -420,7 +422,8 @@
assertTrue(stateResidency.id == j);
assertTrue(stateResidency.totalTimeInStateMs == j);
assertTrue(stateResidency.totalStateEntryCount == j);
- assertTrue(stateResidency.lastEntryTimestampMs == j);
+ assertTrue(stateResidency.lastEntryTimestampMs ==
+ j + mPowerStatsLogger.getStartWallTime());
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
index 816bc6b..33385af 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
@@ -1 +1 @@
-include /core/java/android/media/soundtrigger/OWNERS
+include /media/aidl/android/media/soundtrigger_middleware/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 682a80c..5d27552 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -46,8 +46,8 @@
public void test_unrestricted() {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -108,8 +108,8 @@
public void test_restricted() {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(false)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -170,8 +170,8 @@
public void test_autoDetectNotSupported() {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
- .setAutoDetectionSupported(false)
- .setGeoDetectionSupported(false)
+ .setAutoDetectionFeatureSupported(false)
+ .setGeoDetectionFeatureSupported(false)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -232,8 +232,8 @@
public void test_geoDetectNotSupported() {
ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
.setUserConfigAllowed(true)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(false)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(false)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index d2452ea..14e0bbd 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -364,8 +364,8 @@
// the tests.
final boolean geoDetectionEnabled = autoDetectionEnabled;
return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setUserConfigAllowed(true)
.setAutoDetectionEnabled(autoDetectionEnabled)
.setLocationEnabled(geoDetectionEnabled)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index c8dba5f..f1f8b2f 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -90,8 +90,8 @@
private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED =
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(false)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setAutoDetectionEnabled(false)
.setLocationEnabled(true)
.setGeoDetectionEnabled(false)
@@ -100,8 +100,8 @@
private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED =
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(false)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -110,8 +110,8 @@
private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED =
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(true)
- .setAutoDetectionSupported(false)
- .setGeoDetectionSupported(false)
+ .setAutoDetectionFeatureSupported(false)
+ .setGeoDetectionFeatureSupported(false)
.setAutoDetectionEnabled(false)
.setLocationEnabled(true)
.setGeoDetectionEnabled(false)
@@ -120,8 +120,8 @@
private static final ConfigurationInternal CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED =
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(true)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(false)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(false)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(true)
@@ -130,8 +130,8 @@
private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED =
new ConfigurationInternal.Builder(USER_ID)
.setUserConfigAllowed(true)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setAutoDetectionEnabled(false)
.setLocationEnabled(true)
.setGeoDetectionEnabled(false)
@@ -139,8 +139,8 @@
private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED =
new ConfigurationInternal.Builder(USER_ID)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setUserConfigAllowed(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
@@ -149,8 +149,8 @@
private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED =
new ConfigurationInternal.Builder(USER_ID)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setUserConfigAllowed(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
index d319488..8280cdc 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
@@ -44,8 +44,8 @@
@UserIdInt int userId, boolean geoDetectionEnabled) {
return new ConfigurationInternal.Builder(userId)
.setUserConfigAllowed(true)
- .setAutoDetectionSupported(true)
- .setGeoDetectionSupported(true)
+ .setAutoDetectionFeatureSupported(true)
+ .setGeoDetectionFeatureSupported(true)
.setAutoDetectionEnabled(true)
.setLocationEnabled(true)
.setGeoDetectionEnabled(geoDetectionEnabled)
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 11fb002..624c3de 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -144,6 +144,9 @@
private static final long RARE_THRESHOLD = 48 * HOUR_MS;
private static final long RESTRICTED_THRESHOLD = 96 * HOUR_MS;
+ private static final int ASSERT_RETRY_ATTEMPTS = 20;
+ private static final int ASSERT_RETRY_DELAY_MILLISECONDS = 500;
+
/** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
private static boolean isPackageInstalled = true;
@@ -589,16 +592,37 @@
mInjector.mElapsedRealtime);
}
- private void assertBucket(int bucket) {
+ private void assertBucket(int bucket) throws InterruptedException {
assertBucket(bucket, PACKAGE_1);
}
- private void assertBucket(int bucket, String pkg) {
+ private void assertBucket(int bucket, String pkg) throws InterruptedException {
+ int retries = 0;
+ do {
+ if (bucket == getStandbyBucket(mController, pkg)) {
+ // Success
+ return;
+ }
+ Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
+ retries++;
+ } while(retries < ASSERT_RETRY_ATTEMPTS);
+ // try one last time
assertEquals(bucket, getStandbyBucket(mController, pkg));
}
- private void assertNotBucket(int bucket) {
- assertNotEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
+ private void assertNotBucket(int bucket) throws InterruptedException {
+ final String pkg = PACKAGE_1;
+ int retries = 0;
+ do {
+ if (bucket != getStandbyBucket(mController, pkg)) {
+ // Success
+ return;
+ }
+ Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
+ retries++;
+ } while(retries < ASSERT_RETRY_ATTEMPTS);
+ // try one last time
+ assertNotEquals(bucket, getStandbyBucket(mController, pkg));
}
@Test
@@ -996,7 +1020,7 @@
* a low bucket after the RESTRICTED timeout.
*/
@Test
- public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() {
+ public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
assertBucket(STANDBY_BUCKET_ACTIVE);
@@ -1032,7 +1056,7 @@
* a low bucket after the RESTRICTED timeout.
*/
@Test
- public void testRestrictedTimeoutOverridesPredictionLowBucket() {
+ public void testRestrictedTimeoutOverridesPredictionLowBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
// Not long enough to time out into RESTRICTED.
@@ -1055,7 +1079,7 @@
}
@Test
- public void testRestrictedBucketDisabled() {
+ public void testRestrictedBucketDisabled() throws Exception {
mInjector.mIsRestrictedBucketEnabled = false;
// Get the controller to read the new value. Capturing the ContentObserver isn't possible
// at the moment.
@@ -1080,7 +1104,7 @@
}
@Test
- public void testRestrictedBucket_EnabledToDisabled() {
+ public void testRestrictedBucket_EnabledToDisabled() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
@@ -1097,7 +1121,7 @@
}
@Test
- public void testPredictionRaiseFromRestrictedTimeout_highBucket() {
+ public void testPredictionRaiseFromRestrictedTimeout_highBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
// Way past all timeouts. App times out into RESTRICTED bucket.
@@ -1114,7 +1138,7 @@
}
@Test
- public void testPredictionRaiseFromRestrictedTimeout_lowBucket() {
+ public void testPredictionRaiseFromRestrictedTimeout_lowBucket() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
// Way past all timeouts. App times out into RESTRICTED bucket.
@@ -1366,7 +1390,7 @@
}
@Test
- public void testAddActiveDeviceAdmin() {
+ public void testAddActiveDeviceAdmin() throws Exception {
assertActiveAdmins(USER_ID, (String[]) null);
assertActiveAdmins(USER_ID2, (String[]) null);
@@ -1402,7 +1426,7 @@
}
@Test
- public void isActiveDeviceAdmin() {
+ public void isActiveDeviceAdmin() throws Exception {
assertActiveAdmins(USER_ID, (String[]) null);
assertActiveAdmins(USER_ID2, (String[]) null);
@@ -1488,7 +1512,7 @@
}
@Test
- public void testAppUpdateOnRestrictedBucketStatus() {
+ public void testAppUpdateOnRestrictedBucketStatus() throws Exception {
// Updates shouldn't change bucket if the app timed out.
// Way past all timeouts. App times out into RESTRICTED bucket.
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1563,7 +1587,7 @@
}
@Test
- public void testSystemHeadlessAppElevated() {
+ public void testSystemHeadlessAppElevated() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
PACKAGE_SYSTEM_HEADFULL);
@@ -1589,7 +1613,7 @@
}
@Test
- public void testWellbeingAppElevated() {
+ public void testWellbeingAppElevated() throws Exception {
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_WELLBEING);
assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_WELLBEING);
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 80a046a..9ac755f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -17,6 +17,8 @@
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS;
@@ -205,6 +207,52 @@
}
@Test
+ public void testEnsureFilters_newServiceWithMetadata_onlyOneListed() {
+ ServiceInfo si = new ServiceInfo();
+ si.packageName = "new";
+ si.name = "comp";
+ si.metaData = new Bundle();
+ si.metaData.putInt(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, 2);
+
+ mListeners.ensureFilters(si, 0);
+
+ assertThat(mListeners.getNotificationListenerFilter(
+ Pair.create(si.getComponentName(), 0)).getTypes())
+ .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
+ }
+
+ @Test
+ public void testEnsureFilters_newServiceWithMetadata_disabledTypes() {
+ ServiceInfo si = new ServiceInfo();
+ si.packageName = "new";
+ si.name = "comp";
+ si.metaData = new Bundle();
+ si.metaData.putString(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, "1,2");
+
+ mListeners.ensureFilters(si, 0);
+
+ assertThat(mListeners.getNotificationListenerFilter(
+ Pair.create(si.getComponentName(), 0)).getTypes())
+ .isEqualTo(FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING);
+ }
+
+ @Test
+ public void testEnsureFilters_newServiceWithMetadata_metaDataDisagrees() {
+ ServiceInfo si = new ServiceInfo();
+ si.packageName = "new";
+ si.name = "comp";
+ si.metaData = new Bundle();
+ si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1,2");
+ si.metaData.putInt(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, 1);
+
+ mListeners.ensureFilters(si, 0);
+
+ assertThat(mListeners.getNotificationListenerFilter(
+ Pair.create(si.getComponentName(), 0)).getTypes())
+ .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
+ }
+
+ @Test
public void testEnsureFilters_newServiceWithEmptyMetadata() {
ServiceInfo si = new ServiceInfo();
si.packageName = "new";
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 488e629..d8e7582 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -555,9 +555,10 @@
activity.setRequestedOrientation(
isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
- // Asserts it has orientation derived from bounds.
- assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
+ // Asserts it has orientation derived requested orientation (fixed orientation letterbox).
+ assertEquals(isScreenPortrait ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE,
activity.getConfiguration().orientation);
+ assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
}
@Test
@@ -1964,17 +1965,17 @@
// Non-resizable
mAtm.mForceResizableActivities = false;
- mAtm.mSizeCompatFreeform = false;
+ mAtm.mSupportsNonResizableMultiWindow = false;
assertFalse(activity.supportsFreeform());
// Force resizable
mAtm.mForceResizableActivities = true;
- mAtm.mSizeCompatFreeform = false;
+ mAtm.mSupportsNonResizableMultiWindow = false;
assertTrue(activity.supportsFreeform());
// Allow non-resizable
mAtm.mForceResizableActivities = false;
- mAtm.mSizeCompatFreeform = true;
+ mAtm.mSupportsNonResizableMultiWindow = true;
assertTrue(activity.supportsFreeform());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 47cf53b..074ef36 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -323,4 +323,16 @@
assertFalse(navBarSource.getFrame().isEmpty());
assertTrue(imeSource.getFrame().contains(navBarSource.getFrame()));
}
+
+ @UseTestDisplay
+ @Test
+ public void testDisplayPolicyNotCrash() {
+ final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+
+ // Verify if modules initialized after DisplayContent ctr throws NPE.
+ displayPolicy.onDisplayInfoChanged(mDisplayInfo);
+ displayPolicy.onConfigurationChanged();
+ displayPolicy.onOverlayChangedLw();
+ displayPolicy.release();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index f91c9d0..e9c356d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -171,7 +171,7 @@
final Rect activityBounds = new Rect(mFirstActivity.getBounds());
// DAG is portrait (860x1200), so Task and Activity fill DAG.
- assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+ assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
assertThat(taskBounds).isEqualTo(dagBounds);
assertThat(activityBounds).isEqualTo(taskBounds);
@@ -194,8 +194,8 @@
final Rect activityConfigBounds =
new Rect(mFirstActivity.getConfiguration().windowConfiguration.getBounds());
- // DAG is landscape (1200x860), Task fills parent
- assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+ // DAG is landscape (1200x860), no fixed orientation letterbox
+ assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -211,7 +211,7 @@
}
@Test
- public void testLaunchLandscapeApp_taskIsLetterboxInDisplayAreaGroup() {
+ public void testLaunchLandscapeApp_activityIsLetterboxForFixedOrientationInDisplayAreaGroup() {
mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
@@ -221,17 +221,18 @@
final Rect taskBounds = new Rect(mFirstTask.getBounds());
final Rect activityBounds = new Rect(mFirstActivity.getBounds());
- // DAG is portrait (860x1200), so Task is letterbox (860x[860x860/1200=616])
- assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
+ // DAG is portrait (860x1200), and activity is letterboxed for fixed orientation
+ // (860x[860x860/1200=616]). Task fills DAG.
+ assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
- assertThat(taskBounds.width()).isEqualTo(dagBounds.width());
- assertThat(taskBounds.height())
+ assertThat(taskBounds).isEqualTo(dagBounds);
+ assertThat(activityBounds.width()).isEqualTo(dagBounds.width());
+ assertThat(activityBounds.height())
.isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height());
- assertThat(activityBounds).isEqualTo(taskBounds);
}
@Test
- public void testLaunchLandscapeApp_taskLetterboxBecomesActivityLetterboxAfterRotation() {
+ public void testLaunchLandscapeApp_fixedOrientationLetterboxBecomesSizeCompatAfterRotation() {
mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
@@ -245,9 +246,8 @@
final Rect newTaskBounds = new Rect(mFirstTask.getBounds());
final Rect newActivityBounds = new Rect(mFirstActivity.getBounds());
- // DAG is landscape (1200x860), Task fills parent
- // Task letterbox size
- assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+ // DAG is landscape (1200x860), no fixed orientation letterbox
+ assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -311,7 +311,7 @@
}
@Test
- public void testResizableFixedOrientationApp_taskLevelLetterboxing() {
+ public void testResizableFixedOrientationApp_fixedOrientationLetterboxing() {
mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
@@ -324,7 +324,7 @@
assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
- assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+ assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
// Launch portrait on second DAG
@@ -336,13 +336,13 @@
assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
assertThat(mSecondRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
assertThat(mSecondActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
- assertThat(mSecondTask.isTaskLetterboxed()).isFalse();
+ assertThat(mSecondActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
assertThat(mSecondActivity.inSizeCompatMode()).isFalse();
// First activity is letterboxed in portrait as requested.
assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
- assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
+ assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
}
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 e843dd7..b73c664 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -23,6 +23,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -43,7 +44,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.same;
@@ -126,6 +126,7 @@
// Put app window into freeform and then make it a compat app.
final Rect bounds = new Rect(100, 100, 400, 600);
mTask.setBounds(bounds);
+
prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
assertEquals(bounds, mActivity.getBounds());
@@ -194,12 +195,7 @@
new TestDisplayContent.Builder(mAtm, 1000, 2000)
.setDensityDpi(200).build();
- mActivity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
- .setMaxAspectRatio(1.5f)
- .build();
- mActivity.mVisibleRequested = true;
+ prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
final Rect originalBounds = new Rect(mActivity.getBounds());
final int originalDpi = mActivity.getConfiguration().densityDpi;
@@ -566,18 +562,18 @@
.setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.build();
- assertTrue(activity.shouldUseSizeCompatMode());
+ assertTrue(activity.shouldCreateCompatDisplayInsets());
// The non-resizable activity should not be size compat because it is on a resizable task
// in multi-window mode.
mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
- assertFalse(activity.shouldUseSizeCompatMode());
+ assertFalse(activity.shouldCreateCompatDisplayInsets());
// The non-resizable activity should not be size compat because the display support
// changing windowing mode from fullscreen to freeform.
mTask.mDisplayContent.setDisplayWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
- assertFalse(activity.shouldUseSizeCompatMode());
+ assertFalse(activity.shouldCreateCompatDisplayInsets());
}
@Test
@@ -597,7 +593,7 @@
SizeCompatTests.class.getName()))
.setUid(android.os.Process.myUid())
.build();
- assertFalse(activity.shouldUseSizeCompatMode());
+ assertFalse(activity.shouldCreateCompatDisplayInsets());
}
@Test
@@ -653,7 +649,7 @@
}
@Test
- public void testDisplayIgnoreOrientationRequest_fixedOrientationAppLaunchedInTaskLetterbox() {
+ public void testDisplayIgnoreOrientationRequest_fixedOrientationAppLaunchedLetterbox() {
// Set up a display in landscape and ignoring orientation request.
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -662,7 +658,6 @@
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
- final Rect taskBounds = new Rect(mTask.getBounds());
final Rect activityBounds = new Rect(mActivity.getBounds());
// Display shouldn't be rotated.
@@ -670,19 +665,19 @@
mActivity.mDisplayContent.getLastOrientation());
assertTrue(displayBounds.width() > displayBounds.height());
- // App should launch in task level letterboxing.
- assertTrue(mTask.isTaskLetterboxed());
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
- assertEquals(taskBounds, activityBounds);
- // Task bounds should be 700x1400 with the ratio as the display.
- assertEquals(displayBounds.height(), taskBounds.height());
+ // Activity bounds should be 700x1400 with the ratio as the display.
+ assertEquals(displayBounds.height(), activityBounds.height());
assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
- taskBounds.width());
+ activityBounds.width());
}
@Test
- public void testDisplayIgnoreOrientationRequest_taskLetterboxBecameSizeCompatAfterRotate() {
+ public void
+ testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() {
// Set up a display in landscape and ignoring orientation request.
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -700,7 +695,7 @@
assertTrue(displayBounds.width() < displayBounds.height());
// App should be in size compat.
- assertFalse(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
assertEquals(activityBounds.width(), newActivityBounds.width());
assertEquals(activityBounds.height(), newActivityBounds.height());
@@ -719,7 +714,7 @@
Rect activityBounds = new Rect(mActivity.getBounds());
// App should launch in fullscreen.
- assertFalse(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertEquals(displayBounds, activityBounds);
@@ -731,7 +726,7 @@
assertTrue(displayBounds.width() > displayBounds.height());
// App should be in size compat.
- assertFalse(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
// App bounds should be 700x1400 with the ratio as the display.
@@ -741,7 +736,7 @@
}
@Test
- public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInTaskLetterbox() {
+ public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInLetterbox() {
// Set up a display in landscape and ignoring orientation request.
setUpDisplaySizeWithApp(2800, 1400);
final DisplayContent display = mActivity.mDisplayContent;
@@ -750,7 +745,7 @@
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mTask.isTaskLetterboxed());
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Launch another portrait fixed app.
@@ -765,19 +760,19 @@
// Update with new activity requested orientation and recompute bounds with no previous
// size compat cache.
verify(mTask).onDescendantOrientationChanged(same(newActivity));
- verify(mTask).computeFullscreenBounds(any(), any());
final Rect displayBounds = new Rect(display.getBounds());
final Rect taskBounds = new Rect(mTask.getBounds());
final Rect newActivityBounds = new Rect(newActivity.getBounds());
- // Task and app bounds should be 700x1400 with the ratio as the display.
- assertTrue(mTask.isTaskLetterboxed());
+ // Task and display bounds should be equal while activity should be letterboxed and
+ // has 700x1400 bounds with the ratio as the display.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
- assertEquals(taskBounds, newActivityBounds);
- assertEquals(displayBounds.height(), taskBounds.height());
+ assertEquals(taskBounds, displayBounds);
+ assertEquals(displayBounds.height(), newActivityBounds.height());
assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
- taskBounds.width());
+ newActivityBounds.width());
}
@Test
@@ -790,7 +785,7 @@
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mTask.isTaskLetterboxed());
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Launch another portrait fixed app with max aspect ratio as 1.3.
@@ -806,21 +801,20 @@
// Update with new activity requested orientation and recompute bounds with no previous
// size compat cache.
verify(mTask).onDescendantOrientationChanged(same(newActivity));
- verify(mTask).computeFullscreenBounds(any(), any());
final Rect displayBounds = new Rect(display.getBounds());
final Rect taskBounds = new Rect(mTask.getBounds());
final Rect newActivityBounds = new Rect(newActivity.getBounds());
- // Task bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
- assertTrue(mTask.isTaskLetterboxed());
- assertEquals(displayBounds.height(), taskBounds.height());
- assertEquals((long) Math.rint(taskBounds.height() / newActivity.info.maxAspectRatio),
- taskBounds.width());
+ // Task bounds should fill parent bounds.
+ assertEquals(displayBounds, taskBounds);
- // App bounds should be fullscreen in Task bounds.
+ // Activity bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
- assertEquals(taskBounds, newActivityBounds);
+ assertEquals(displayBounds.height(), newActivityBounds.height());
+ assertEquals((long) Math.rint(newActivityBounds.height() / newActivity.info.maxAspectRatio),
+ newActivityBounds.width());
}
@Test
@@ -834,26 +828,23 @@
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
clearInvocations(mActivity);
- assertTrue(mTask.isTaskLetterboxed());
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
- assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
// Rotate display to portrait.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
// App should be in size compat.
- assertFalse(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
- assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
final Rect activityBounds = new Rect(mActivity.getBounds());
mTask.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */);
// App still in size compat, and the bounds don't change.
verify(mActivity, never()).clearSizeCompatMode();
- assertFalse(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
- assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
assertEquals(activityBounds, mActivity.getBounds());
}
@@ -867,22 +858,22 @@
// Portrait fixed app.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
- // In Task letterbox
- assertTrue(mTask.isTaskLetterboxed());
+ // In fixed orientation letterbox
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Rotate display to portrait.
rotateDisplay(display, ROTATION_90);
// App should be in size compat.
- assertFalse(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
// Rotate display to landscape.
rotateDisplay(display, ROTATION_180);
// In Task letterbox
- assertTrue(mTask.isTaskLetterboxed());
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
}
@@ -898,22 +889,22 @@
// Landscape fixed app.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE);
- // In Task letterbox
- assertTrue(mTask.isTaskLetterboxed());
+ // In fixed orientation letterbox
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
// Rotate display to portrait.
rotateDisplay(display, ROTATION_90);
// App should be in size compat.
- assertFalse(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
// Rotate display to landscape.
rotateDisplay(display, ROTATION_180);
- // In Task letterbox
- assertTrue(mTask.isTaskLetterboxed());
+ // In fixed orientation letterbox
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
}
@@ -972,21 +963,21 @@
addWindowToActivity(mActivity);
mActivity.mRootWindowContainer.performSurfacePlacement();
- // Split screen is also in portrait [1000,1400], so Task should be in letterbox, and
- // activity fills task.
- assertEquals(ORIENTATION_LANDSCAPE, mTask.getConfiguration().orientation);
+ // Split screen is also in portrait [1000,1400], so activty should be in fixed orientation
+ // letterbox.
+ assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation);
assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation);
assertFitted();
- assertTrue(mTask.isTaskLetterboxed());
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
- // Letterbox should fill the gap between the split screen and the letterboxed task.
+ // Letterbox should fill the gap between the split screen and the letterboxed activity.
final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds());
- final Rect letterboxedTaskBounds = new Rect(mTask.getBounds());
- assertTrue(primarySplitBounds.contains(letterboxedTaskBounds));
- assertEquals(new Rect(letterboxedTaskBounds.left - primarySplitBounds.left,
- letterboxedTaskBounds.top - primarySplitBounds.top,
- primarySplitBounds.right - letterboxedTaskBounds.right,
- primarySplitBounds.bottom - letterboxedTaskBounds.bottom),
+ final Rect letterboxedBounds = new Rect(mActivity.getBounds());
+ assertTrue(primarySplitBounds.contains(letterboxedBounds));
+ assertEquals(new Rect(letterboxedBounds.left - primarySplitBounds.left,
+ letterboxedBounds.top - primarySplitBounds.top,
+ primarySplitBounds.right - letterboxedBounds.right,
+ primarySplitBounds.bottom - letterboxedBounds.bottom),
mActivity.getLetterboxInsets());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 4984799..a1e5afb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -661,7 +661,7 @@
@Test
public void testForceMaximizesUnresizeableApp() {
- mAtm.mSizeCompatFreeform = false;
+ mAtm.mSupportsNonResizableMultiWindow = false;
final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
@@ -683,12 +683,12 @@
}
@Test
- public void testLaunchesAppInWindowOnFreeformDisplay() {
- mAtm.mSizeCompatFreeform = true;
+ public void testLaunchesPortraitSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
+ mAtm.mSupportsNonResizableMultiWindow = true;
final TestDisplayContent freeformDisplay = createNewDisplayContent(
WINDOWING_MODE_FREEFORM);
- Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
+ Rect expectedLaunchBounds = new Rect(0, 0, 100, 200);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -699,6 +699,7 @@
mCurrent.mBounds.set(expectedLaunchBounds);
mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
assertEquals(RESULT_CONTINUE,
new CalculateRequestBuilder().setOptions(options).calculate());
@@ -710,6 +711,38 @@
}
@Test
+ public void testLaunchesLandscapeSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
+ mAtm.mSupportsNonResizableMultiWindow = true;
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
+ WINDOWING_MODE_FREEFORM);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE;
+ assertEquals(RESULT_CONTINUE,
+ new CalculateRequestBuilder().setOptions(options).calculate());
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testLaunchesPortraitUnresizableOnFreeformDisplayWithFreeformSizeCompat() {
+ mAtm.mSupportsNonResizableMultiWindow = true;
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
+ WINDOWING_MODE_FREEFORM);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+ assertEquals(RESULT_CONTINUE,
+ new CalculateRequestBuilder().setOptions(options).calculate());
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 0eb8c8d..d853b93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -266,8 +266,9 @@
root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(root, task.getRootActivity());
assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
- assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
- assertEquals(fullScreenBounds.height(), task.getBounds().height());
+ // Portrait orientation is enforced on activity level. Task should fill fullscreen bounds.
+ assertThat(task.getBounds().height()).isLessThan(task.getBounds().width());
+ assertEquals(fullScreenBounds, task.getBounds());
// Top activity gets used
final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setParentTask(stack)
@@ -286,8 +287,11 @@
// Fix the display orientation to portrait which is 90 degrees for the test display.
dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
- assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
- assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+ // Fixed orientation request should be resolved on activity level. Task fills display
+ // bounds.
+ assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
+ assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
+ assertEquals(fullScreenBoundsPort, task.getBounds());
// in FREEFORM, no constraint
final Rect freeformBounds = new Rect(display.getBounds());
@@ -297,10 +301,11 @@
task.setBounds(freeformBounds);
assertEquals(freeformBounds, task.getBounds());
- // FULLSCREEN letterboxes bounds
+ // FULLSCREEN letterboxes bounds on activity level, no constraint on task level.
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
- assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+ assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
+ assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
+ assertEquals(fullScreenBoundsPort, task.getBounds());
// FREEFORM restores bounds as before
stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -327,9 +332,10 @@
assertEquals(fullScreenBounds, task.getBounds());
- // Setting app to fixed portrait fits within parent
+ // Setting app to fixed portrait fits within parent on activity level. Task fills parent.
root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
+ assertThat(root.getBounds().width()).isLessThan(root.getBounds().height());
+ assertEquals(task.getBounds(), fullScreenBounds);
assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getOrientation());
}
@@ -424,7 +430,8 @@
// to the input bounds.
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
final ActivityRecord.CompatDisplayInsets compatIntsets =
- new ActivityRecord.CompatDisplayInsets(display, activity);
+ new ActivityRecord.CompatDisplayInsets(
+ display, activity, /* fixedOrientationBounds= */ null);
task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 1c0f640..c3eb5c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -257,24 +257,4 @@
task.resolveOverrideConfiguration(parentConfig);
assertThat(resolvedOverride.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
}
-
- @Test
- public void testCleanUpActivityReferences_clearLastTaskBoundsComputeActivity() {
- final Task rootTask = createTaskStackOnDisplay(mDisplayContent);
- final Task leafTask = createTaskInStack(rootTask, 0 /* userId */);
- final ActivityRecord activity2 = createActivityRecord(mDisplayContent, leafTask);
- final ActivityRecord activity1 = createActivityRecord(mDisplayContent, leafTask);
- activity1.finishing = false;
- leafTask.resolveOverrideConfiguration(rootTask.getConfiguration());
-
- assertEquals(activity1, leafTask.getLastTaskBoundsComputeActivity());
-
- leafTask.cleanUpActivityReferences(activity2);
-
- assertNotNull(leafTask.getLastTaskBoundsComputeActivity());
-
- leafTask.cleanUpActivityReferences(activity1);
-
- assertNull(leafTask.getLastTaskBoundsComputeActivity());
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 0dd8d23..18c8cf5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -18,7 +18,6 @@
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
@@ -119,20 +118,6 @@
}
@Test
- public void testEnableSizeCompatFreeform() {
- try (BoolSettingsSession enableSizeCompatFreeformSession = new
- BoolSettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
- final boolean enableSizeCompatFreeform =
- !enableSizeCompatFreeformSession.getSetting();
- final Uri enableSizeCompatFreeformUri =
- enableSizeCompatFreeformSession.setSetting(enableSizeCompatFreeform);
- mWm.mSettingsObserver.onChange(false, enableSizeCompatFreeformUri);
-
- assertEquals(mWm.mAtmService.mSizeCompatFreeform, enableSizeCompatFreeform);
- }
- }
-
- @Test
public void testSupportsNonResizableMultiWindow() {
try (BoolSettingsSession supportsNonResizableMultiWindowSession = new
BoolSettingsSession(DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)) {
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 c13d6b1..ebc5c4f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -538,9 +538,8 @@
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy) {
- final DisplayContent display =
+ final DisplayContent dc =
new TestDisplayContent.Builder(mAtm, info).build();
- final DisplayContent dc = display.mDisplayContent;
// this display can show IME.
dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy);
return dc;
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index 6aadd23..b6244b8 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -20,19 +20,28 @@
import static android.content.Context.TRANSLATION_MANAGER_SERVICE;
import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.translation.ITranslationManager;
import android.view.translation.TranslationSpec;
import android.view.translation.UiTranslationManager.UiTranslationState;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
/**
@@ -48,6 +57,8 @@
private static final String TAG = "TranslationManagerService";
+ private static final int MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS = 2 * 60_000; // 2 minutes
+
public TranslationManagerService(Context context) {
// TODO: Discuss the disallow policy
super(context, new FrameworkResourcesServiceNameResolver(context,
@@ -60,19 +71,82 @@
return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled);
}
+ @Override
+ protected void enforceCallingPermissionForManagement() {
+ getContext().enforceCallingPermission(MANAGE_UI_TRANSLATION, TAG);
+ }
+
+ @Override
+ protected int getMaximumTemporaryServiceDurationMs() {
+ return MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS;
+ }
+
+ @Override
+ protected void dumpLocked(String prefix, PrintWriter pw) {
+ super.dumpLocked(prefix, pw);
+ }
+
private void enforceCallerHasPermission(String permission) {
final String msg = "Permission Denial from pid =" + Binder.getCallingPid() + ", uid="
+ Binder.getCallingUid() + " doesn't hold " + permission;
getContext().enforceCallingPermission(permission, msg);
}
+ /** True if the currently set handler service is not overridden by the shell. */
+ @GuardedBy("mLock")
+ private boolean isDefaultServiceLocked(int userId) {
+ final String defaultServiceName = mServiceNameResolver.getDefaultServiceName(userId);
+ if (defaultServiceName == null) {
+ return false;
+ }
+
+ final String currentServiceName = mServiceNameResolver.getServiceName(userId);
+ return defaultServiceName.equals(currentServiceName);
+ }
+
+ /** True if the caller of the api is the same app which hosts the TranslationService. */
+ @GuardedBy("mLock")
+ private boolean isCalledByServiceAppLocked(int userId, @NonNull String methodName) {
+ final int callingUid = Binder.getCallingUid();
+
+ final String serviceName = mServiceNameResolver.getServiceName(userId);
+ if (serviceName == null) {
+ Slog.e(TAG, methodName + ": called by UID " + callingUid
+ + ", but there's no service set for user " + userId);
+ return false;
+ }
+
+ final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+ if (serviceComponent == null) {
+ Slog.w(TAG, methodName + ": invalid service name: " + serviceName);
+ return false;
+ }
+
+ final String servicePackageName = serviceComponent.getPackageName();
+ final PackageManager pm = getContext().getPackageManager();
+ final int serviceUid;
+ try {
+ serviceUid = pm.getPackageUidAsUser(servicePackageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, methodName + ": could not verify UID for " + serviceName);
+ return false;
+ }
+ if (callingUid != serviceUid) {
+ Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is "
+ + serviceUid);
+ return false;
+ }
+ return true;
+ }
+
final class TranslationManagerServiceStub extends ITranslationManager.Stub {
@Override
public void getSupportedLocales(IResultReceiver receiver, int userId)
throws RemoteException {
synchronized (mLock) {
final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
+ if (service != null && (isDefaultServiceLocked(userId)
+ || isCalledByServiceAppLocked(userId, "getSupportedLocales"))) {
service.getSupportedLocalesLocked(receiver);
} else {
Slog.v(TAG, "getSupportedLocales(): no service for " + userId);
@@ -86,7 +160,8 @@
int sessionId, IResultReceiver receiver, int userId) throws RemoteException {
synchronized (mLock) {
final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
+ if (service != null && (isDefaultServiceLocked(userId)
+ || isCalledByServiceAppLocked(userId, "onSessionCreated"))) {
service.onSessionCreatedLocked(sourceSpec, destSpec, sessionId, receiver);
} else {
Slog.v(TAG, "onSessionCreated(): no service for " + userId);
@@ -102,12 +177,35 @@
enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
synchronized (mLock) {
final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
+ if (service != null && (isDefaultServiceLocked(userId)
+ || isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) {
service.updateUiTranslationState(state, sourceSpec, destSpec, viewIds,
taskId);
}
}
}
+
+ /**
+ * Dump the service state into the given stream. You run "adb shell dumpsys translation".
+ */
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (mLock) {
+ dumpLocked("", pw);
+ }
+ }
+
+ @Override
+ public void onShellCommand(@Nullable FileDescriptor in,
+ @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err,
+ @NonNull String[] args,
+ @Nullable ShellCallback callback,
+ @NonNull ResultReceiver resultReceiver) throws RemoteException {
+ new TranslationManagerServiceShellCommand(
+ TranslationManagerService.this).exec(this, in, out, err, args, callback,
+ resultReceiver);
+ }
}
@Override // from SystemService
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java
new file mode 100644
index 0000000..ba1b390
--- /dev/null
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java
@@ -0,0 +1,79 @@
+/*
+ * 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.translation;
+
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/** Handles adb shell commands send to TranslationManagerService. */
+public class TranslationManagerServiceShellCommand extends ShellCommand {
+ private final TranslationManagerService mService;
+
+ TranslationManagerServiceShellCommand(TranslationManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ if ("set".equals(cmd)) {
+ return requestSet(pw);
+ }
+ return handleDefaultCommands(cmd);
+ }
+
+ private int requestSet(PrintWriter pw) {
+ final String what = getNextArgRequired();
+ if ("temporary-service".equals(what)) {
+ return setTemporaryService(pw);
+ }
+ pw.println("Invalid set: " + what);
+ return -1;
+ }
+
+ private int setTemporaryService(PrintWriter pw) {
+ final int userId = Integer.parseInt(getNextArgRequired());
+ final String serviceName = getNextArg();
+ if (serviceName == null) {
+ mService.resetTemporaryService(userId);
+ return 0;
+ }
+ final int duration = Integer.parseInt(getNextArgRequired());
+ mService.setTemporaryService(userId, serviceName, duration);
+ pw.println("TranslationService temporarily set to " + serviceName + " for "
+ + duration + "ms");
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ try (PrintWriter pw = getOutPrintWriter();) {
+ pw.println("Translation Service (translation) commands:");
+ pw.println(" help");
+ pw.println(" Prints this help text.");
+ pw.println("");
+ pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+ pw.println(" Temporarily (for DURATION ms) changes the service implementation.");
+ pw.println(" To reset, call with just the USER_ID argument.");
+ pw.println("");
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 35e65c1..ed71d17 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -22,25 +22,49 @@
import android.content.Intent;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
+import android.media.AudioAttributes;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.service.voice.AlwaysOnHotwordDetector;
import android.service.voice.HotwordDetectionService;
import android.service.voice.IDspHotwordDetectionCallback;
import android.service.voice.IHotwordDetectionService;
+import android.util.Pair;
import android.util.Slog;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.infra.ServiceConnector;
+import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintWriter;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
/**
* A class that provides the communication with the HotwordDetectionService.
*/
final class HotwordDetectionConnection {
- static final String TAG = "HotwordDetectionConnection";
+ private static final String TAG = "HotwordDetectionConnection";
// TODO (b/177502877): Set the Debug flag to false before shipping.
- static final boolean DEBUG = true;
+ private static final boolean DEBUG = true;
+
+ // Number of bytes per sample of audio (which is a short).
+ private static final int BYTES_PER_SAMPLE = 2;
+ // TODO: These constants need to be refined.
+ private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
+ private static final long VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS = 2000;
+ private static final int MAX_STREAMING_SECONDS = 10;
+
+ private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
+ // TODO: This may need to be a Handler(looper)
+ private final ScheduledExecutorService mScheduledExecutorService =
+ Executors.newSingleThreadScheduledExecutor();
final Object mLock;
final ComponentName mDetectionComponentName;
@@ -93,42 +117,106 @@
}
}
- private void detectFromDspSource(int sessionId, IDspHotwordDetectionCallback callback) {
+ private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
+ IHotwordRecognitionStatusCallback externalCallback) {
if (DEBUG) {
Slog.d(TAG, "detectFromDspSource");
}
+
+ AudioRecord record = createAudioRecord(recognitionEvent);
+
+ Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
+
+ if (clientPipe == null) {
+ // Error.
+ // Need to propagate as unknown error or something?
+ return;
+ }
+ ParcelFileDescriptor audioSink = clientPipe.second;
+ ParcelFileDescriptor clientRead = clientPipe.first;
+
+ record.startRecording();
+
+ mAudioCopyExecutor.execute(() -> {
+ try (OutputStream fos =
+ new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) {
+ byte[] buffer = new byte[1024];
+
+ while (true) {
+ int bytesRead = record.read(buffer, 0, 1024);
+
+ if (bytesRead < 0) {
+ break;
+ }
+
+ fos.write(buffer, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed supplying audio data to validator", e);
+ }
+ });
+
+ Runnable cancellingJob = () -> {
+ record.stop();
+ bestEffortCloseFileDescriptor(audioSink);
+ // TODO: consider calling externalCallback.onRejected(ERROR_TIMEOUT).
+ };
+
+ ScheduledFuture<?> cancelingFuture =
+ mScheduledExecutorService.schedule(
+ cancellingJob, VALIDATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+ // TODO: consider making this a non-anonymous class.
+ IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
+ @Override
+ public void onDetected() throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "onDetected");
+ }
+ bestEffortCloseFileDescriptor(audioSink);
+ cancelingFuture.cancel(true);
+
+ // Give 2 more seconds for the interactor to start consuming the mic. If it fails to
+ // do so under the given time, we'll force-close the mic to make sure resources are
+ // freed up.
+ // TODO: consider modelling these 2 seconds in the API.
+ mScheduledExecutorService.schedule(
+ cancellingJob,
+ VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS,
+ TimeUnit.MILLISECONDS);
+
+ externalCallback.onKeyphraseDetected(recognitionEvent);
+ }
+
+ @Override
+ public void onRejected() throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "onRejected");
+ }
+ cancelingFuture.cancel(true);
+ externalCallback.onRejected(
+ AlwaysOnHotwordDetector.HOTWORD_DETECTION_FALSE_ALERT);
+ }
+ };
+
mRemoteHotwordDetectionService.run(
- service -> service.detectFromDspSource(sessionId, callback));
+ service -> service.detectFromDspSource(
+ clientRead,
+ recognitionEvent.getCaptureFormat(),
+ VALIDATION_TIMEOUT_MILLIS,
+ internalCallback));
+ bestEffortCloseFileDescriptor(clientRead);
}
static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
private SoundTrigger.KeyphraseRecognitionEvent mRecognitionEvent;
private final HotwordDetectionConnection mHotwordDetectionConnection;
private final IHotwordRecognitionStatusCallback mExternalCallback;
- private final IDspHotwordDetectionCallback mInternalCallback;
SoundTriggerCallback(IHotwordRecognitionStatusCallback callback,
HotwordDetectionConnection connection) {
mHotwordDetectionConnection = connection;
mExternalCallback = callback;
- mInternalCallback = new IDspHotwordDetectionCallback.Stub() {
- @Override
- public void onDetected() throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "onDetected");
- }
- mExternalCallback.onKeyphraseDetected(mRecognitionEvent);
- }
-
- @Override
- public void onRejected() throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "onRejected");
- }
- mExternalCallback.onRejected(
- AlwaysOnHotwordDetector.HOTWORD_DETECTION_FALSE_ALERT);
- }
- };
}
@Override
@@ -142,7 +230,7 @@
if (useHotwordDetectionService) {
mRecognitionEvent = recognitionEvent;
mHotwordDetectionConnection.detectFromDspSource(
- recognitionEvent.getCaptureSession(), mInternalCallback);
+ recognitionEvent, mExternalCallback);
} else {
mExternalCallback.onKeyphraseDetected(recognitionEvent);
}
@@ -171,6 +259,48 @@
}
}
+ // TODO: figure out if we need to let the client configure some of the parameters.
+ private static AudioRecord createAudioRecord(
+ @NonNull SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) {
+ int sampleRate = recognitionEvent.getCaptureFormat().getSampleRate();
+ return new AudioRecord(
+ new AudioAttributes.Builder()
+ .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(),
+ recognitionEvent.getCaptureFormat(),
+ getBufferSizeInBytes(sampleRate, MAX_STREAMING_SECONDS),
+ recognitionEvent.getCaptureSession());
+ }
+
+ /**
+ * Returns the number of bytes required to store {@code bufferLengthSeconds} of audio sampled at
+ * {@code sampleRate} Hz, using the format returned by DSP audio capture.
+ */
+ private static int getBufferSizeInBytes(int sampleRate, int bufferLengthSeconds) {
+ return BYTES_PER_SAMPLE * sampleRate * bufferLengthSeconds;
+ }
+
+ private static Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() {
+ ParcelFileDescriptor[] fileDescriptors;
+ try {
+ fileDescriptors = ParcelFileDescriptor.createPipe();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to create audio stream pipe", e);
+ return null;
+ }
+
+ return Pair.create(fileDescriptors[0], fileDescriptors[1]);
+ }
+
+ private static void bestEffortCloseFileDescriptor(ParcelFileDescriptor fd) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Failed closing file descriptor", e);
+ }
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mBound="); pw.println(mBound);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 8628f89..dce63eb 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -76,6 +76,7 @@
import android.util.Log;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceActionCheckCallback;
@@ -643,6 +644,10 @@
}
ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
+ if (prefPackage == null) {
+ prefPackage = getDefaultRecognizer();
+ }
+
List<ResolveInfo> available =
mContext.getPackageManager().queryIntentServicesAsUser(
new Intent(RecognitionService.SERVICE_INTERFACE),
@@ -670,6 +675,12 @@
}
}
+ @Nullable
+ public String getDefaultRecognizer() {
+ String recognizer = mContext.getString(R.string.config_systemSpeechRecognizer);
+ return TextUtils.isEmpty(recognizer) ? null : recognizer;
+ }
+
ComponentName getCurRecognizer(int userHandle) {
String curRecognizer = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5cf8de8..f20ee7e 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -138,6 +138,24 @@
* }
* }
* }
+ *
+ * </pre>
+ * <p id="companionInCallService">
+ * <h3>Access to InCallService for Wearable Devices</h3>
+ * <ol>
+ * If your app is a third-party companion app and wants to access InCallService APIs, what your
+ * app could do are:
+ * <p>
+ * <ol>
+ * <li> Declare MANAGE_ONGOING_CALLS permission in your manifest
+ * <li> Associate with a physical wearable device via the
+ * {@link android.companion.CompanionDeviceManager} API as a companion app. See:
+ * https://developer.android.com/guide/topics/connectivity/companion-device-pairing
+ * <li> Implement this InCallService with BIND_INCALL_SERVICE permission
+ * </ol>
+ * </ol>
+ * <p>
+ *
* </pre>
* <p id="incomingCallNotification">
* <h3>Showing the Incoming Call Notification</h3>
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 472d639..17749e8 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1702,22 +1702,22 @@
}
/**
- * Returns whether the caller has {@link InCallService} access for companion apps.
- *
- * A companion app is an app associated with a physical wearable device via the
- * {@link android.companion.CompanionDeviceManager} API.
+ * Returns whether the caller has {@link android.Manifest.permission#MANAGE_ONGOING_CALLS}
+ * permission. The permission can be obtained by associating with a physical wearable device
+ * via the {@link android.companion.CompanionDeviceManager} API as a companion app. If the
+ * caller app has the permission, it has {@link InCallService} access to manage ongoing calls.
*
* @return {@code true} if the caller has {@link InCallService} access for
* companion app; {@code false} otherwise.
*/
- public boolean hasCompanionInCallServiceAccess() {
+ public boolean hasManageOngoingCallsPermission() {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.hasCompanionInCallServiceAccess(
+ return service.hasManageOngoingCallsPermission(
mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling hasCompanionInCallServiceAccess().", e);
+ Log.e(TAG, "RemoteException calling hasManageOngoingCallsPermission().", e);
if (!isSystemProcess()) {
e.rethrowAsRuntimeException();
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 88ef1b0..eb106b5 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -179,9 +179,9 @@
boolean isInCall(String callingPackage, String callingFeatureId);
/**
- * @see TelecomServiceImpl#hasCompanionInCallServiceAccess
+ * @see TelecomServiceImpl#hasManageOngoingCallsPermission
*/
- boolean hasCompanionInCallServiceAccess(String callingPackage);
+ boolean hasManageOngoingCallsPermission(String callingPackage);
/**
* @see TelecomServiceImpl#isInManagedCall
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3d43d03..b52f4919 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -33,7 +33,11 @@
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.ImsSsData;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.telephony.Rlog;
@@ -1717,8 +1721,14 @@
* Configs used for APN setup.
*/
public static final class Apn {
- /** Prefix of all Apn.KEY_* constants. */
- private static final String KEY_PREFIX = "apn.";
+ /**
+ * Prefix of all Apn.KEY_* constants.
+ *
+ * @deprecated Since KEY_PREFIX is unnecessary to public, it will modify to private
+ * next android generation.
+ */
+ @Deprecated
+ public static final String KEY_PREFIX = "apn.";
/** IPv4 internet protocol */
public static final String PROTOCOL_IPV4 = "IP";
@@ -3666,14 +3676,13 @@
/** Prefix of all ImsServiceEntitlement.KEY_* constants. */
public static final String KEY_PREFIX = "imsserviceentitlement.";
-
/** The address of the entitlement configuration server. */
- public static final String KEY_AES_URL_STRING = KEY_PREFIX + "aes_url_string";
-
+ public static final String KEY_ENTITLEMENT_SERVER_URL_STRING =
+ KEY_PREFIX + "entitlement_server_url_string";
private static PersistableBundle getDefaults() {
PersistableBundle defaults = new PersistableBundle();
- defaults.putString(KEY_AES_URL_STRING, "");
+ defaults.putString(KEY_ENTITLEMENT_SERVER_URL_STRING, "");
return defaults;
}
}
@@ -4001,6 +4010,43 @@
KEY_PREFIX + "enable_presence_publish_bool";
/**
+ * Each string in this array contains a mapping between the service-id and version portion
+ * of the service-description element and the associated IMS feature tag(s) that are
+ * associated with each element (see RCC.07 Table 7).
+ * <p>
+ * Each string contains 3 parts, which define the mapping between service-description and
+ * feature tag(s) that must be present in the IMS REGISTER for the RCS service to be
+ * published as part of the RCS PUBLISH procedure:
+ * [service-id]|[version]|[desc]|[feature_tag];[feature_tag];...
+ * <ul>
+ * <li>[service-id]: the service-id element associated with the RCS capability.</li>
+ * <li>[version]: The version element associated with that service-id</li>
+ * <li>[desc]: The optional desecription element associated with that service-id</li>
+ * <li>[feature_tag];[feature_tag]: The list of all feature tags associated with this
+ * capability that MUST ALL be present in the IMS registration for this this
+ * capability to be published to the network.</li>
+ * </ul>
+ * <p>
+ * Features managed by the framework will be considered capable when the ImsService reports
+ * that those services are capable via the
+ * {@link MmTelFeature#notifyCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities)} or
+ * {@link RcsFeature#notifyCapabilitiesStatusChanged(RcsFeature.RcsImsCapabilities)} APIs.
+ * For RCS services not managed by the framework, the capability of these services are
+ * determined by looking at the feature tags associated with the IMS registration using the
+ * {@link ImsRegistrationAttributes} API and mapping them to the service-description map.
+ * <p>
+ * The framework contains a default value of this key, which is based off of RCC.07
+ * specification. Capabilities based of carrier extensions may be added to this list on a
+ * carrier-by-carrier basis as required in order to support additional services in the
+ * PUBLISH. If this list contains a service-id and version that overlaps with the default,
+ * it will override the framework default.
+ * @hide
+ */
+ @SystemApi
+ public static final String KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY =
+ KEY_PREFIX + "publish_service_desc_feature_tag_map_override_string_array";
+
+ /**
* Flag indicating whether or not this carrier supports the exchange of phone numbers with
* the carrier's RCS presence server in order to retrieve the RCS capabilities of requested
* contacts used in the RCS User Capability Exchange (UCE) procedure. See RCC.71, section 3
@@ -4059,6 +4105,8 @@
defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000);
defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
+ defaults.putStringArray(KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY,
+ new String[] {});
defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index af67ed2..fe7e5976 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -187,7 +187,7 @@
return mIsSystemThresholdReportingRequestedWhileIdle;
}
- /*
+ /**
* @return the live token of the request
*
* @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f64f428..61e809b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -29,6 +29,7 @@
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -8579,6 +8580,9 @@
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
@SystemApi
public boolean setAllowedNetworkTypes(@NetworkTypeBitMask long allowedNetworkTypes) {
try {
@@ -8670,6 +8674,9 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
public void setAllowedNetworkTypesForReason(@AllowedNetworkTypesReason int reason,
@NetworkTypeBitMask long allowedNetworkTypes) {
if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -8708,6 +8715,9 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresFeature(
+ enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+ value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
@AllowedNetworkTypesReason int reason) {
if (!isValidAllowedNetworkTypesReason(reason)) {
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 5eb75e7..bdf628b 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -21,6 +21,7 @@
import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.net.Uri;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -39,6 +40,15 @@
public final class RcsContactPresenceTuple implements Parcelable {
/**
+ * The service ID used to indicate that service discovery via presence is available.
+ * <p>
+ * See RCC.07 v5.0 specification for more information.
+ * @hide
+ */
+ public static final String SERVICE_ID_PRESENCE =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp";
+
+ /**
* The service ID used to indicate that MMTEL service is available.
* <p>
* See the GSMA RCC.07 specification for more information.
@@ -329,6 +339,13 @@
public @NonNull @DuplexMode List<String> getUnsupportedDuplexModes() {
return Collections.unmodifiableList(mUnsupportedDuplexModeList);
}
+
+ @Override
+ public String toString() {
+ return "servCaps{" + "a=" + mIsAudioCapable + ", v=" + mIsVideoCapable
+ + ", supported=" + mSupportedDuplexModeList + ", unsupported="
+ + mUnsupportedDuplexModeList + '}';
+ }
}
/**
@@ -487,4 +504,36 @@
public @Nullable ServiceCapabilities getServiceCapabilities() {
return mServiceCapabilities;
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("{");
+ if (Build.IS_ENG) {
+ builder.append("u=");
+ builder.append(mContactUri);
+ } else {
+ builder.append("u=");
+ builder.append(mContactUri != null ? "XXX" : "null");
+ }
+ builder.append(", id=");
+ builder.append(mServiceId);
+ builder.append(", v=");
+ builder.append(mServiceVersion);
+ builder.append(", s=");
+ builder.append(mStatus);
+ if (mTimestamp != null) {
+ builder.append(", timestamp=");
+ builder.append(mTimestamp);
+ }
+ if (mServiceDescription != null) {
+ builder.append(", servDesc=");
+ builder.append(mServiceDescription);
+ }
+ if (mServiceCapabilities != null) {
+ builder.append(", servCaps=");
+ builder.append(mServiceCapabilities);
+ }
+ builder.append("}");
+ return builder.toString();
+ }
}
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index fe85502..9299fed 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -344,4 +345,39 @@
public @NonNull Uri getContactUri() {
return mContactUri;
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("RcsContactUceCapability");
+ if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) {
+ builder.append("(presence) {");
+ } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) {
+ builder.append("(options) {");
+ } else {
+ builder.append("(?) {");
+ }
+ if (Build.IS_ENG) {
+ builder.append("uri=");
+ builder.append(mContactUri);
+ } else {
+ builder.append("uri (isNull)=");
+ builder.append(mContactUri != null ? "XXX" : "null");
+ }
+ builder.append(", sourceType=");
+ builder.append(mSourceType);
+ builder.append(", requestResult=");
+ builder.append(mRequestResult);
+
+ if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) {
+ builder.append(", presenceTuples={");
+ builder.append(mPresenceTuples);
+ builder.append("}");
+ } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) {
+ builder.append(", featureTags={");
+ builder.append(mFeatureTags);
+ builder.append("}");
+ }
+
+ return builder.toString();
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
index 4967e5d..6295548 100644
--- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
+++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
@@ -25,7 +25,6 @@
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
-import android.util.Log;
import java.util.List;
@@ -44,30 +43,12 @@
* Respond to a remote capability request from the contact specified with the
* capabilities of this device.
* @param ownCapabilities The capabilities of this device.
- * @hide
- */
- default void onRespondToCapabilityRequest(
- @NonNull RcsContactUceCapability ownCapabilities) {}
-
- /**
- * Respond to a remote capability request from the contact specified with the
- * capabilities of this device.
- * @param ownCapabilities The capabilities of this device.
* @param isBlocked Whether or not the user has blocked the number requesting the
* capabilities of this device. If true, the device should respond to the OPTIONS
* request with a 200 OK response and no capabilities.
*/
- default void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities,
- boolean isBlocked) {
- Log.w("CapabilityExchangeEventListener", "implement "
- + "onRespondToCapabilityRequest(RcsContactUceCapability, boolean) instead!");
- // Fall back to old implementation
- if (isBlocked) {
- onRespondToCapabilityRequestWithError(200, "OK");
- } else {
- onRespondToCapabilityRequest(ownCapabilities);
- }
- }
+ void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities,
+ boolean isBlocked);
/**
* Respond to a remote capability request from the contact specified with the
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index cc050be..34984e0 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -37,6 +37,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
import java.util.HashMap;
/**
@@ -368,7 +369,13 @@
}
private void onNotifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) {
- mRcsConfigData = isCompressed ? RcsConfig.decompressGzip(config) : config;
+ // cache uncompressed config
+ config = isCompressed ? RcsConfig.decompressGzip(config) : config;
+ if (Arrays.equals(mRcsConfigData, config)) {
+ return;
+ }
+ mRcsConfigData = config;
+
// can be null in testing
if (mRcsCallbacks != null) {
mRcsCallbacks.broadcastAction(c -> {
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 5f8e93d..8ad40ed 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -57,10 +57,10 @@
} else if (listener != null && mListener == null) {
mListener = listener;
} else {
- // Fail fast here instead of silently overwriting the listener to another
- // listener due to another connection connecting.
- throw new IllegalStateException("ImsEcbmImplBase: Listener already set by "
- + "another connection.");
+ // Warn that the listener is being replaced while active
+ Log.w(TAG, "setListener is being called when there is already an active "
+ + "listener");
+ mListener = listener;
}
}
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index 8e961ac..ec1c7b3 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -62,10 +62,10 @@
} else if (listener != null && mListener == null) {
mListener = listener;
} else {
- // Fail fast here instead of silently overwriting the listener to another
- // listener due to another connection connecting.
- throw new IllegalStateException("ImsMultiEndpointImplBase: Listener already"
- + " set by another connection.");
+ // Warn that the listener is being replaced while active
+ Log.w(TAG, "setListener is being called when there is already an active "
+ + "listener");
+ mListener = listener;
}
}
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index 83b89aa..eb3e8ed 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -224,11 +224,10 @@
} else if (listener != null && mUtListener == null) {
mUtListener = new ImsUtListener(listener);
} else {
- // This is a limitation of the current API surface, there can only be one
- // listener connected. Fail fast instead of silently overwriting the other
- // listener.
- throw new IllegalStateException("ImsUtImplBase#setListener: listener already "
- + "set by another connected interface!");
+ // Warn that the listener is being replaced while active
+ Log.w(TAG, "setListener is being called when there is already an active "
+ + "listener");
+ mUtListener = new ImsUtListener(listener);
}
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 0048d53..e87f3d9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2325,6 +2325,16 @@
void triggerRcsReconfiguration(int subId);
/**
+ * Enables or disables the test mode for RCS VoLTE single registration.
+ */
+ void setRcsSingleRegistrationTestModeEnabled(boolean enabled);
+
+ /**
+ * Gets the test mode for RCS VoLTE single registration.
+ */
+ boolean getRcsSingleRegistrationTestModeEnabled();
+
+ /**
* Overrides the config of RCS VoLTE single registration enabled for the device.
*/
void setDeviceSingleRegistrationEnabledOverride(String enabled);
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 38a88d3..26afb79 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
@@ -153,31 +153,11 @@
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.navBarLayerIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- fun navBarLayerIsAlwaysVisible_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerIsAlwaysVisible()
- }
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.statusBarLayerIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- fun statusBarLayerIsAlwaysVisible_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.statusBarLayerIsAlwaysVisible()
- }
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
@Presubmit
@Test
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 476708c..2c4c627 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
@@ -17,9 +17,8 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -85,55 +84,55 @@
}
}
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
- @Postsubmit
+ @Presubmit
@Test
fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
- @FlakyTest
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
- @FlakyTest
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
- @Postsubmit
+ @Presubmit
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() =
testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
- @Postsubmit
+ @Presubmit
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
- @Postsubmit
+ @Presubmit
@Test
fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
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 ac140f5..2bcdcd9 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
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -91,63 +91,54 @@
}
}
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
- @Postsubmit
+ @Presubmit
@Test
fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
- @Postsubmit
+ @Presubmit
@Test
fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
Surface.ROTATION_0)
- @Postsubmit
+ @Presubmit
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
- @Postsubmit
+ @Presubmit
@Test
fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
- @Postsubmit
+ @Presubmit
@Test
- fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(testSpec.isRotated)
+ fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
- @FlakyTest
- @Test
- fun navBarLayerRotatesAndScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() {
Assume.assumeFalse(testSpec.isRotated)
@@ -171,7 +162,8 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 5,
+ supportedRotations = listOf(Surface.ROTATION_0))
}
}
}
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 c7a5178..6b2b930 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
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -89,43 +89,43 @@
}
}
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
- @Postsubmit
+ @Presubmit
@Test
fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
- @Postsubmit
+ @Presubmit
@Test
fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
- @Postsubmit
+ @Presubmit
@Test
fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`)
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() {
Assume.assumeFalse(testSpec.isRotated)
@@ -139,7 +139,7 @@
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
}
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() {
Assume.assumeFalse(testSpec.isRotated)
@@ -168,7 +168,8 @@
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(repetitions = 5)
+ .getConfigNonRotationTests(repetitions = 5,
+ supportedRotations = listOf(Surface.ROTATION_0))
}
}
}
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 e2a258a..18fac6a 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
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.launch
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -148,17 +147,35 @@
@Test
fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
- @Postsubmit
+ @Presubmit
@Test
- fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ Assume.assumeFalse(testSpec.isRotated)
testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
@FlakyTest
@Test
- fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
- @FlakyTest(bugId = 141361128)
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ @FlakyTest
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ @Presubmit
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(Surface.ROTATION_0,
testSpec.config.endRotation)
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index ad5bbf2..18a9331 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -55,14 +55,14 @@
.build()
private val dataFromPasspoint = CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
.setCaptive(true)
.apply {
if (SdkLevel.isAtLeastS()) {
setVenueFriendlyName("venue friendly name")
+ setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+ setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
}
}
.build()
@@ -96,28 +96,28 @@
if (SdkLevel.isAtLeastS()) {
assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
- }
- assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint")) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/other"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/passpoint")) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/other"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint")) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/other"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/passpoint")) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/other"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ }
}
@Test
diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
new file mode 100644
index 0000000..56b56ef
--- /dev/null
+++ b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
@@ -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 android.net
+
+import android.net.ConnectivityManager.TYPE_NONE
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.InetAddresses.parseNumericAddress
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.net.Inet4Address
+import java.net.Inet6Address
+
+private const val TEST_IMSI = "imsi1"
+private const val TEST_SSID = "SSID1"
+private const val TEST_NETID = 123
+
+private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
+private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
+private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
+private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
+private val TEST_IFACE = "fake0"
+private val TEST_LINK_PROPERTIES = LinkProperties().apply {
+ interfaceName = TEST_IFACE
+ addLinkAddress(TEST_IPV4_LINKADDR)
+ addLinkAddress(TEST_IPV6_LINKADDR)
+
+ // Add default routes
+ addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
+ addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
+}
+
+private val TEST_CAPABILITIES = NetworkCapabilities().apply {
+ addTransportType(TRANSPORT_WIFI)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
+ setSSID(TEST_SSID)
+}
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+class NetworkStateSnapshotTest {
+
+ @Test
+ fun testParcelUnparcel() {
+ val emptySnapshot = NetworkStateSnapshot(LinkProperties(), NetworkCapabilities(),
+ Network(TEST_NETID), null, TYPE_NONE)
+ val snapshot = NetworkStateSnapshot(
+ TEST_LINK_PROPERTIES, TEST_CAPABILITIES, Network(TEST_NETID), TEST_IMSI, TYPE_WIFI)
+ assertParcelSane(emptySnapshot, 5)
+ assertParcelSane(snapshot, 5)
+ }
+}
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
index 4d1e337..56f9df7 100644
--- a/tests/net/integration/Android.bp
+++ b/tests/net/integration/Android.bp
@@ -35,7 +35,7 @@
"android.test.mock",
],
static_libs: [
- "TestNetworkStackLib",
+ "NetworkStackApiStableLib",
"androidx.test.ext.junit",
"frameworks-net-integration-testutils",
"kotlin-reflect",
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index dc9e587..e1da3d0 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -84,6 +85,7 @@
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
diff --git a/tests/net/java/android/net/NetworkIdentityTest.kt b/tests/net/java/android/net/NetworkIdentityTest.kt
new file mode 100644
index 0000000..eb2b85c
--- /dev/null
+++ b/tests/net/java/android/net/NetworkIdentityTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net
+
+import android.net.NetworkIdentity.OEM_NONE
+import android.net.NetworkIdentity.OEM_PAID
+import android.net.NetworkIdentity.OEM_PRIVATE
+import android.net.NetworkIdentity.getOemBitfield
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertEquals
+
+@RunWith(JUnit4::class)
+class NetworkIdentityTest {
+ @Test
+ fun testGetOemBitfield() {
+ val oemNone = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
+ }
+ val oemPaid = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
+ }
+ val oemPrivate = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
+ }
+ val oemAll = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
+ }
+
+ assertEquals(getOemBitfield(oemNone), OEM_NONE)
+ assertEquals(getOemBitfield(oemPaid), OEM_PAID)
+ assertEquals(getOemBitfield(oemPrivate), OEM_PRIVATE)
+ assertEquals(getOemBitfield(oemAll), OEM_PAID or OEM_PRIVATE)
+ }
+}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index b39555d..27224c2 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -20,14 +20,23 @@
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.NetworkIdentity.SUBTYPE_COMBINED
+import android.net.NetworkIdentity.OEM_NONE;
+import android.net.NetworkIdentity.OEM_PAID;
+import android.net.NetworkIdentity.OEM_PRIVATE;
import android.net.NetworkIdentity.buildNetworkIdentity
import android.net.NetworkStats.DEFAULT_NETWORK_ALL
import android.net.NetworkStats.METERED_ALL
import android.net.NetworkStats.ROAMING_ALL
+import android.net.NetworkTemplate.MATCH_ETHERNET
import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
+import android.net.NetworkTemplate.OEM_MANAGED_ALL
+import android.net.NetworkTemplate.OEM_MANAGED_NO
+import android.net.NetworkTemplate.OEM_MANAGED_YES
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
import android.telephony.TelephonyManager
import com.android.testutils.assertParcelSane
@@ -37,9 +46,11 @@
import org.junit.runners.JUnit4
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
+import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
+import kotlin.test.fail
private const val TEST_IMSI1 = "imsi1"
private const val TEST_IMSI2 = "imsi2"
@@ -57,13 +68,18 @@
private fun buildNetworkState(
type: Int,
subscriberId: String? = null,
- ssid: String? = null
+ ssid: String? = null,
+ oemManaged: Int = OEM_NONE,
): NetworkState {
val lp = LinkProperties()
val caps = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
setSSID(ssid)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID,
+ (oemManaged and OEM_PAID) == OEM_PAID)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
+ (oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
}
return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId)
}
@@ -136,11 +152,15 @@
@Test
fun testParcelUnparcel() {
val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE)
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE,
+ OEM_MANAGED_ALL)
val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 0)
- assertParcelSane(templateMobile, 8)
- assertParcelSane(templateWifi, 8)
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL)
+ val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES)
+ assertParcelSane(templateMobile, 9)
+ assertParcelSane(templateWifi, 9)
+ assertParcelSane(templateOem, 9)
}
// Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
@@ -152,4 +172,81 @@
assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
}
}
+
+ @Test
+ fun testOemNetworkConstants() {
+ val constantValues = arrayOf(OEM_MANAGED_YES, OEM_MANAGED_ALL, OEM_MANAGED_NO,
+ OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
+
+ // Verify that "not OEM managed network" constants are equal.
+ assertEquals(OEM_MANAGED_NO, OEM_NONE);
+
+ // Verify the constants don't conflict.
+ assertEquals(constantValues.size, constantValues.distinct().count())
+ }
+
+ /**
+ * Helper to enumerate and assert OEM managed wifi and mobile {@code NetworkTemplate}s match
+ * their the appropriate OEM managed {@code NetworkIdentity}s.
+ *
+ * @param networkType {@code TYPE_MOBILE} or {@code TYPE_WIFI}
+ * @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the
+ * networkType.
+ * @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is
+ * {@code TYPE_MOBILE}. May be left as null when matchType is
+ * {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}.
+ * @param templateSsid Top be populated with {@code TEST_SSID*} only if networkType is
+ * {@code TYPE_WIFI}. May be left as null when matchType is
+ * {@link NetworkTemplate.MATCH_WIFI_WILDCARD}.
+ * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
+ * one of {@code TEST_SSID*}.
+ */
+ private fun matchOemManagedIdent(networkType: Int, matchType:Int, subscriberId: String? = null,
+ templateSsid: String? = null, identSsid: String? = null) {
+ val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
+ // A null subscriberId needs a null matchSubscriberIds argument as well.
+ val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId)
+
+ val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_YES)
+ val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL)
+
+ for (identityOemManagedState in oemManagedStates) {
+ val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType,
+ subscriberId, identSsid, identityOemManagedState), /*defaultNetwork=*/false,
+ /*subType=*/0)
+
+ // Create a template with each OEM managed type and match it against the NetworkIdentity
+ for (templateOemManagedState in oemManagedStates) {
+ val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ NETWORK_TYPE_ALL, templateOemManagedState)
+ if (identityOemManagedState == templateOemManagedState) {
+ template.assertMatches(ident)
+ } else {
+ template.assertDoesNotMatch(ident)
+ }
+ }
+ // OEM_MANAGED_ALL ignores OEM state.
+ templateOemAll.assertMatches(ident)
+ if (identityOemManagedState == OEM_NONE) {
+ // OEM_MANAGED_YES matches everything except OEM_NONE.
+ templateOemYes.assertDoesNotMatch(ident)
+ } else {
+ templateOemYes.assertMatches(ident)
+ }
+ }
+ }
+
+ @Test
+ fun testOemManagedMatchesIdent() {
+ matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1)
+ matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD)
+ matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateSsid = TEST_SSID1,
+ identSsid = TEST_SSID1)
+ matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, identSsid = TEST_SSID1)
+ }
}
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index 866f38c..d04c87b 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 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.
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
new file mode 100644
index 0000000..9b0cfa9
--- /dev/null
+++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.net.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
+import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdChangedListener
+import android.provider.Settings
+import android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI
+import android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import android.test.mock.MockContentResolver
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.R
+import com.android.internal.util.test.FakeSettingsProvider
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.argThat
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+/**
+ * Tests for [MultinetworkPolicyTracker].
+ *
+ * Build, install and run with:
+ * atest android.net.util.MultinetworkPolicyTrackerTest
+ */
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class MultinetworkPolicyTrackerTest {
+ private val resources = mock(Resources::class.java).also {
+ doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
+ }
+ private val telephonyManager = mock(TelephonyManager::class.java)
+ private val subscriptionManager = mock(SubscriptionManager::class.java).also {
+ doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt())
+ }
+ private val resolver = MockContentResolver().apply {
+ addProvider(Settings.AUTHORITY, FakeSettingsProvider()) }
+ private val context = mock(Context::class.java).also {
+ doReturn(Context.TELEPHONY_SERVICE).`when`(it)
+ .getSystemServiceName(TelephonyManager::class.java)
+ doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
+ doReturn(subscriptionManager).`when`(it)
+ .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
+ doReturn(resolver).`when`(it).contentResolver
+ doReturn(resources).`when`(it).resources
+ doReturn(it).`when`(it).createConfigurationContext(any())
+ Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
+ }
+ private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
+
+ private fun assertMultipathPreference(preference: Int) {
+ Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
+ preference.toString())
+ tracker.updateMeteredMultipathPreference()
+ assertEquals(preference, tracker.meteredMultipathPreference)
+ }
+
+ @Test
+ fun testUpdateMeteredMultipathPreference() {
+ assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
+ assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY)
+ assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE)
+ }
+
+ @Test
+ fun testUpdateAvoidBadWifi() {
+ Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
+ assertTrue(tracker.updateAvoidBadWifi())
+ assertFalse(tracker.avoidBadWifi)
+
+ doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
+ assertTrue(tracker.updateAvoidBadWifi())
+ assertTrue(tracker.avoidBadWifi)
+ }
+
+ @Test
+ fun testOnActiveDataSubscriptionIdChanged() {
+ val testSubId = 1000
+ val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */,
+ "TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */,
+ "123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */,
+ ""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */,
+ "1"/* cardString */)
+ doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId)
+
+ // Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in
+ // MultinetworkPolicyTracker should be also updated after subId changed.
+ Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
+ Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
+ MULTIPATH_PREFERENCE_PERFORMANCE.toString())
+
+ val listenerCaptor = ArgumentCaptor.forClass(
+ ActiveDataSubscriptionIdChangedListener::class.java)
+ verify(telephonyManager, times(1))
+ .registerPhoneStateListener(any(), listenerCaptor.capture())
+ val listener = listenerCaptor.value
+ listener.onActiveDataSubscriptionIdChanged(testSubId)
+
+ // Check it get resource value with test sub id.
+ verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId)
+ verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 })
+
+ // Check if avoidBadWifi and meteredMultipathPreference values have been updated.
+ assertFalse(tracker.avoidBadWifi)
+ assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference)
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 6de1075..1cfc3f9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2797,6 +2797,10 @@
NetworkCapabilities filter = new NetworkCapabilities();
filter.addCapability(capability);
+ // Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add
+ // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
+ // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
+ filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
handlerThread.start();
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -4144,6 +4148,7 @@
handlerThread.start();
NetworkCapabilities filter = new NetworkCapabilities()
.addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_INTERNET);
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter, mCsHandlerThread);
@@ -6048,6 +6053,7 @@
.addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkDownstreamBandwidthKbps(10);
final NetworkCapabilities wifiNc = new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
@@ -6056,6 +6062,7 @@
.addCapability(NET_CAPABILITY_NOT_ROAMING)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkUpstreamBandwidthKbps(20);
mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
@@ -7748,19 +7755,13 @@
mWiFiNetworkAgent.removeCapability(testCap);
callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
- // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
- // it.
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
- }
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
mCellNetworkAgent.removeCapability(testCap);
callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
callbackWithoutCap.assertNoCallback();
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkClearDefault();
- }
+ verify(mMockNetd).networkClearDefault();
mCm.unregisterNetworkCallback(callbackWithCap);
mCm.unregisterNetworkCallback(callbackWithoutCap);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 435c3c0..505ff9b 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkIdentity.OEM_NONE;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
@@ -213,7 +214,7 @@
final NetworkStats.Entry entry = new NetworkStats.Entry();
final NetworkIdentitySet identSet = new NetworkIdentitySet();
identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- TEST_IMSI, null, false, true, true));
+ TEST_IMSI, null, false, true, true, OEM_NONE));
int myUid = Process.myUid();
int otherUidInSameUser = Process.myUid() + 1;
@@ -468,7 +469,7 @@
final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
final NetworkIdentitySet ident = new NetworkIdentitySet();
ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
- false, true, true));
+ false, true, true, OEM_NONE));
large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index 291efc7..9fa1c50 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkIdentity.OEM_NONE;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.METERED_NO;
@@ -220,7 +221,7 @@
identSet.add(new NetworkIdentity(
TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
IMSI_1, null /* networkId */, false /* roaming */, true /* metered */,
- true /* defaultNetwork */));
+ true /* defaultNetwork */, OEM_NONE));
return identSet;
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index d644739..54d6fb9 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -21,6 +21,9 @@
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkIdentity.OEM_NONE;
+import static android.net.NetworkIdentity.OEM_PAID;
+import static android.net.NetworkIdentity.OEM_PRIVATE;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -40,7 +43,10 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
+import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.net.NetworkTemplate.OEM_MANAGED_NO;
+import static android.net.NetworkTemplate.OEM_MANAGED_YES;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
import static android.net.NetworkTemplate.buildTemplateWifi;
@@ -643,6 +649,116 @@
assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2);
}
+ @Test
+ public void testMobileStatsOemManaged() throws Exception {
+ final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID);
+
+ final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE);
+
+ final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_PAID | OEM_PRIVATE);
+
+ final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES);
+
+ final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO);
+
+ // OEM_PAID network comes online.
+ NetworkState[] states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+ new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 36L, 41L, 24L, 96L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // OEM_PRIVATE network comes online.
+ states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+ new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 49L, 71L, 72L, 48L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // OEM_PAID + OEM_PRIVATE network comes online.
+ states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+ new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
+ NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 57L, 86L, 83L, 93L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // OEM_NONE network comes online.
+ states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 29L, 73L, 34L, 31L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // Verify OEM_PAID template gets only relevant stats.
+ assertUidTotal(templateOemPaid, UID_RED, 36L, 41L, 24L, 96L, 0);
+
+ // Verify OEM_PRIVATE template gets only relevant stats.
+ assertUidTotal(templateOemPrivate, UID_RED, 49L, 71L, 72L, 48L, 0);
+
+ // Verify OEM_PAID + OEM_PRIVATE template gets only relevant stats.
+ assertUidTotal(templateOemAll, UID_RED, 57L, 86L, 83L, 93L, 0);
+
+ // Verify OEM_NONE sees only non-OEM managed stats.
+ assertUidTotal(templateOemNone, UID_RED, 29L, 73L, 34L, 31L, 0);
+
+ // Verify OEM_MANAGED_YES sees all OEM managed stats.
+ assertUidTotal(templateOemYes, UID_RED,
+ 36L + 49L + 57L,
+ 41L + 71L + 86L,
+ 24L + 72L + 83L,
+ 96L + 48L + 93L, 0);
+
+ // Verify ALL_MOBILE template gets both OEM managed and non-OEM managed stats.
+ assertUidTotal(sTemplateImsi1, UID_RED,
+ 36L + 49L + 57L + 29L,
+ 41L + 71L + 86L + 73L,
+ 24L + 72L + 83L + 34L,
+ 96L + 48L + 93L + 31L, 0);
+ }
+
// TODO: support per IMSI state
private void setMobileRatTypeAndWaitForIdle(int ratType) {
when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString()))
@@ -1488,6 +1604,20 @@
return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null);
}
+ private static NetworkState buildOemManagedMobileState(String subscriberId, boolean isRoaming,
+ int[] oemNetCapabilities) {
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(TEST_IFACE);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
+ for (int nc : oemNetCapabilities) {
+ capabilities.setCapability(nc, true);
+ }
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
+ }
+
private long getElapsedRealtime() {
return mElapsedRealtime;
}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
new file mode 100644
index 0000000..28cf38a
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeTrafficSelectorUtilsTest {
+ private static final int START_PORT = 16;
+ private static final int END_PORT = 65520;
+
+ private static final InetAddress IPV4_START_ADDRESS =
+ InetAddresses.parseNumericAddress("192.0.2.100");
+ private static final InetAddress IPV4_END_ADDRESS =
+ InetAddresses.parseNumericAddress("192.0.2.101");
+
+ private static final InetAddress IPV6_START_ADDRESS =
+ InetAddresses.parseNumericAddress("2001:db8:2::100");
+ private static final InetAddress IPV6_END_ADDRESS =
+ InetAddresses.parseNumericAddress("2001:db8:2::101");
+
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeTrafficSelector ts) {
+ final PersistableBundle bundle = IkeTrafficSelectorUtils.toPersistableBundle(ts);
+ final IkeTrafficSelector resultTs = IkeTrafficSelectorUtils.fromPersistableBundle(bundle);
+ assertEquals(ts, resultTs);
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessIpv4Ts() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeTrafficSelector(START_PORT, END_PORT, IPV4_START_ADDRESS, IPV4_END_ADDRESS));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessIpv6Ts() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeTrafficSelector(START_PORT, END_PORT, IPV6_START_ADDRESS, IPV6_END_ADDRESS));
+ }
+}
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index ebc0ec1..e775e1a 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -11,12 +11,6 @@
EMOJI_VS = 0xFE0F
-#TODO(179952916): Rename CutiveMono and DancingScript
-CANONICAL_NAME_EXCEPTION_LIST = [
- 'CutiveMono.ttf',
- 'DancingScript-Regular.ttf',
-]
-
LANG_TO_SCRIPT = {
'as': 'Beng',
'be': 'Cyrl',
@@ -703,8 +697,6 @@
def check_canonical_name():
for record in _all_fonts:
file_name, index = record.font
- if file_name in CANONICAL_NAME_EXCEPTION_LIST:
- continue
if index and index != 0:
continue
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 4342d4e..039bb4e 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -34,9 +34,13 @@
srcs: [
"tests/**/*.kt",
],
+ test_options: {
+ unit_test: true,
+ },
static_libs: [
"protologtool-lib",
"junit",
"mockito",
+ "objenesis",
],
}